在indexedDB中捕获错误和回滚

问题描述 投票:1回答:2

我必须在这里遗漏一些非常基本的东西,并希望你能提供任何方向。谢谢。

以下代码是我认为在catch中的中止事务的注释掉的try-catch处于活动状态时正在工作的代码。中止事务在每个先前成功的req上触发req.onerror,每个req都反过来触发transaction.onerror和过多的递归错误。我解决了这个问题,不知道多少,认为一切正常,以至于个别请求错误触发了req.onerror并回滚了事务。然而,似乎只有捕获中的中止声明才能解决这个问题。我通过发送无法解析为JSON字符串的错误数据来测试错误情况。

但是,现在,我在一个场景中使用相同的代码而不需要try-catch和后续中止,我无法触发req.onerror并且不明白为什么。

传递给DB_pop的参数是一个对象,它包含对象存储的名称,数据对象的数组以及“add”或“put”的字符串。我故意传递一个好的数据对象和一个带有空键的数据对象,如下面的第一个代码语句所示。好的人写的,坏的不写。 req.onerror和transaction.onerror不会触发。只有transaction.oncomplete触发。此外,只有一个req.onsuccess触发。我得出结论是因为写入控制台日志的内容。

连接到调用DB_pop函数的promise的then语句运行拒绝函数。回滚函数运行,关闭then清除变量以防止内存泄漏运行。我不明白这一点,因为如果只触发transaction.oncomplete,它应该解决而不是拒绝。

为什么没有req.onerror触发第二个数据对象并导致事务回滚并删除写入的第一个数据对象?

我尝试使req成为一个数组,并且还删除了d循环并使用null键传递单个数据对象,并且都没有发生错误事件。

我注意到如果在现有密钥上将错误伪装成数据库的add,那么所有错误事件都会触发,甚至直到数据库open / create中设置的一般错误事件。似乎put中的空键不会按预期和回滚触发错误。

p = DB_pop( { 'os' : 'topics', 'data' : [ { 'key' : 0, 'gap' : T.gap, 'max' : T.max, 'selKey' : key }, { 'key' : null, 'title' : t, 'created' : d, 'edited' : d } ], 'op' : 'put' } ); 

p.then( () => { T.title = t; }, rollback ).then( () => {  evt = key = t = T = d = p = m = null; console.log('cleaned up'); } );




  function DB_pop( o )  // ( os, data, op )
    { 
      return new Promise( ( resolve, reject ) =>
        {
          if ( !DB_open.base ) reject( 'Failed to populate database ' + DB_open.title + ' because the database is closed or does not exist.' );

          let t = DB_open.base.transaction( [ o.os ], 'readwrite' ),
              s = t.objectStore( o.os ),
              req, d;

          DB_pop.error = false;

          function free_RAM() 
           { 
             t = s = req = d = null;
           } // close free_RAM

             t.oncomplete = ( e ) =>
               {
                 console.log('trans complete');
                 resolve();
                 free_RAM();
                 e = null;
               }; // close t.oncomplete

             t.onerror = ( e ) =>
               {
                 //e.stopPropagation(); // Stop propagation up to the database error level in the database open block.
                 DB_pop.error = true;
                 reject(e);
                 console.log( 'Transaction error : ' + e.target.error );
                 free_RAM();
                 e = null;
               }; // close t.onerror

             t.onabort = ( e ) =>
               {
                 console.log( 'Transaction aborted : ' + e.target.error );
                 free_RAM();
                 e = null;
               }; // close t.onabort


            for ( d of o.data )
              { 

               // try
               //   { let q = JSON.parse( { 'x' : d, 'y' : 3 }   ); }
               // catch(e)
                //  { t.abort(); error = true; break; }  //?????????? Test what takes place if the try fails.

                req = s[ o.op ]( d );  // o.op is either 'add' or 'put'.
                req.k = d.key; 
                req.n = d.nbr;

                req.onsuccess = function( e )
                  {
                    if ( !DB_pop.error )
                      {
                        console.log( 'Success at k = ' + this.k  + '.' );
                      }; // end if
                  }; // close req.onsuccess

                req.onerror = function( e ) 
                  { 
                    /*
                       When a transaction is rolled back/aborted, every request's error event is fired and propagates up to transaction.onerror and causes a "too much recursion" error.
                       Thus, let it propagate once and, within transaction.onerror, set error to true.
                    */

                    console.log( 'Request.onerror fired. Error = ' + e.target.error + ' k = ' + this.k + ', n = ' + this.n );

                    if ( DB_pop.error )
                      {
                        e.stopPropagation();
                        console.log( 'Stopping propagation' );
                      }; // end if
                  }; // close req.onerror

              }; // next d

        }); //  close promise

    } // close DB_pop
indexeddb
2个回答
3
投票

IDBObjectStore.put投掷DataError,因为提供的密钥无效。这将退出该函数并阻止创建(或执行)请求 - 因此永远不会调用请求回调。

事务正常完成,因为所有先前执行的DB操作都成功。 promise本身失败,因为函数在尝试创建无效请求的行上引发了异常:

req = s[ o.op ]( d );

您可以在您的promise的错误处理程序中显式调用abort,或者在处理函数中捕获异常。


0
投票

我的第一个猜测是因为你在循环中定义了一个函数。关键问题是这种模式:

for(...) {
  request.onsuccess = function() {
    //...
  };
}

有一些有效的方法可以在循环中定义函数,但上面的例子不是一个。在循环中定义函数通常是一个混乱的业务,所以按照惯例,我建议完全避免它。请尝试使用此模式:

function outerfunction() {
   function innerhelperfunction(){}

   for(...) {
     request.onsuccess = innerhelperfunction;
   }
}

例如,参见Javascript: Creating Functions in a For Loop

© www.soinside.com 2019 - 2024. All rights reserved.