我必须在这里遗漏一些非常基本的东西,并希望您能提供任何指导。谢谢。
以下代码是当捕获中的异常中止事务的注释掉try-catch处于活动状态时,我认为可以正常工作的代码。中止事务在每个先前成功的请求上触发一个req.onerror,而每个请求又依次触发transaction.onerror和一个过多的递归错误。我解决了这个问题,但并不了解很多,以为一切工作都很好,因此单个请求错误触发了req.onerror并回滚了事务。但是,似乎只有catch中的中止语句才使该设置无效。我通过发送无法解析为JSON字符串的错误数据来测试错误情况。
但是,现在,我在场景中使用了相同的代码,而无需进行try-catch和随后的中止操作,因此我无法启动req.onerror,也不知道为什么。
传递给DB_pop的参数o是一个对象,其中包含对象存储的名称,数据对象数组以及“ add”或“ put”的字符串。我特意传递了一个好的数据对象和一个带有空键的对象,如下面的第一个代码语句所示。好人写,坏人不写。 req.onerror和transaction.onerror不会触发。只有transaction.oncomplete触发。同样,只有一个要求成功触发。我之所以得出这样的结论是因为要写入控制台日志。
连接到调用DB_pop函数的promise的then
语句运行拒绝函数。运行回滚功能,并运行用于清理变量以防止内存泄漏的结束then
。我也不明白,因为如果仅触发transaction.oncomplete,它应该解决而不是拒绝。
为什么第二个数据对象不会引发req.onerror并导致事务回滚并删除写入的第一个数据对象?
我尝试使req成为数组,并且还删除了d循环并使用空键传递了一个数据对象,并且均未触发onerror事件。
我确实注意到,如果在现有键上将错误伪造为数据库中的add
,则所有错误事件都会触发,甚至发生在打开/创建数据库中设置的一般错误事件之前。看来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
答案 0 :(得分:4)
IDBObjectStore.put
抛出DataError
,因为提供的密钥无效。这样会退出该函数并阻止创建(或执行)请求,因此永远不会调用请求回调。
由于所有先前执行的数据库操作均成功,因此事务正常完成。 Promise本身失败,因为该函数在尝试创建无效请求的行上引发了异常:
req = s[ o.op ]( d );
您可以在错误处理程序中显式调用abort
来实现您的promise或在处理函数中捕获异常。
答案 1 :(得分:0)
我的第一个猜测是因为您在循环中定义了一个函数。关键问题是这种模式:
for(...) {
request.onsuccess = function() {
//...
};
}
有一些有效的方法可以在循环中定义函数,但是上面的示例不是一个。通常,在循环中定义函数是一件麻烦的事情,因此按照惯例,我建议完全避免使用它。请尝试以下模式:
function outerfunction() {
function innerhelperfunction(){}
for(...) {
request.onsuccess = innerhelperfunction;
}
}