在下面的代码中,
Promise.allSettled( [ entry_save(), save_state(), get_HTML() ] ).then( ... );
承诺entry_save
and save_state
都是readwrite
数据库事务和get_HTML
is readonly
。他们俩readwrite
事务可以组合在一起,但这会使维护的撤消/重做链变得复杂,并将两者的成功和回滚联系在一起,这是不希望的。
The entry_save
交易需要在之前写入save_state
交易。搬家前entry_save
进入Promise.allSettled
这就是它的工作原理,因为entry_save
交易是先于其他交易创建的。这MDN 文章 https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction解释了请求执行的顺序如何取决于创建事务的时间,而与发出请求的顺序无关。
我的问题是每个 Promise 进程的同步代码是否按照其放置在数组中的顺序进行,以便放置entry_save
首先总是会导致首先创建其事务并保证首先执行其数据库请求?
虽然它有效并且足够快,但我不想这样做:
entry_save().then( () => { Promise.allSettled( [ save_state(), get_HTML() ] ) } ).then( ... );
如果重要的话,这并不完全是这样写的,它更符合:
entry_save().then( intermediate );
where intermediate
调用Promise.allSettled
.
谢谢。
为了澄清一点,下面是上面引用的 MDN 文档中给出的示例。
var trans1 = db.transaction("foo", "readwrite");
var trans2 = db.transaction("foo", "readwrite");
var objectStore2 = trans2.objectStore("foo")
var objectStore1 = trans1.objectStore("foo")
objectStore2.put("2", "key");
objectStore1.put("1", "key");
After the code is executed the object store should contain the value "2", since trans2 should run after trans1.
If entry_save
创造trans1
and save_state
create trans2
,并且全部在函数的同步代码中,这意味着不在一个函数内onsuccess
or onerror
数据库请求的处理程序或类似的东西,MDN 示例不成立吗?
因此,@jfriend00 写道,
这些函数按照它们在数组中的放置顺序被调用,
但这仅决定了异步的顺序
开始了。
由于事务是在异步代码开始之前在同步代码中创建的,因此这是否会按照事务创建的时间顺序对写入请求进行排序?
我想测试一下,但我不知道如何测试。如果两个几乎相同的 Promise 被用在一个Promise.allSettled
,如何延迟第一个创建的事务的写入请求,使其发生在第二个创建的事务的写入请求之后,以测试是否会先写入? setTimeout 应该终止事务。也许在请求之前放置了一个长时间运行的同步循环。
这个问题最后的代码可能会更好地更准确地说明我试图问的问题。它采用上面引用的文章中的 MDN 示例,并将其分布在两个承诺中Promise.allSettled
,两者都尝试从内部写入同一对象存储onsuccess
的事件get
要求。
问题是,在创建第二个事务之前创建的第一个事务的文章中的相同原理,无论请求的顺序如何,仍然适用于此设置。由于 Promise 的同步部分将按照 Promise 放置在数组中的顺序进行处理,因此 Promise 中的事务p_1
将在之前创建p_2
。但是,那put
请求在onsuccess
事件的get
请求在p_1
由于构建大字符串的循环而延迟。问题是意愿p_1
还是之前写的p_2
?
在尝试这个时,我无法得到p_2
写在之前p_1
。因此,看来 MDN 示例甚至适用于此类设置。但是,我无法确定为什么,因为我不明白 JS 代码是如何真正解释/处理的。
例如,为什么可以req.onsuccess
请求发出后定义函数?我问的是question https://stackoverflow.com/questions/51394399/why-are-indexeddb-requests-made-before-the-event-handlers-are-declared不久前但仍然不知道它不会影响我尝试在此处添加延迟的方式。我知道反过来是行不通的;但我的观点是我不确定浏览器在发出 put 请求之前如何处理该同步循环p_1
真正确定这个示例表明 MDN 文章始终适用于此设置。但是,我可以观察到,随着循环迭代次数的增加,完成请求需要更长的时间;而且,在我观察到的所有情况下,p_1
总是写在前面p_2
。唯一的办法p_2
写在之前p_1
is if p_1
根本不写入,因为字符串占用了太多内存,导致事务在p_1
被中止。
话虽这么说,回到我的问题的更完整的设置,涉及一系列的三个承诺Promise.allSettled
与要求相比entry_save
在开始之前完成Promise.allSettled
关于剩下的两个承诺,在我的项目的完整代码中,出于我不确定的原因,后者比前者更快,即等待entry_save
完成比将其包含在中更快Promise.allSettled
.
我原以为情况会相反。我现在能想到的唯一原因是,因为entry_save
and save_state
都写入同一个对象存储,也许浏览器所做的任何事情都相当于锁定对象存储直到第一个事务,即entry_save
,完成并移除锁所需的时间比要求的时间长entry_save
之前完成Promise.allSettled
开始并且不涉及锁。本以为一切都会“提前”准备好,只等两人put
请求按交易顺序进行。它们按顺序发生,但速度较慢,或者至少不如使用以下命令那么快:
entry_save().then( () => { Promise.allSettled( [ save_state(), get_HTML() ] ) } ).then( ... );
代替:
Promise.allSettled( [ entry_save(), save_state(), get_HTML() ] ).then( ... );
function p_all() { Promise.allSettled( [ p_1(), p_2() ] ); }
function p_1()
{
return new Promise( ( resolve, reject ) =>
{
let T = DB.transaction( [ 'os_1', 'os_2' ], 'readwrite' ),
q = T.objectStore( 'os_1' ),
u = T.objectStore( 'os_2' ),
req, i, t ='', x = '';
req = q.get( 1 );
req.onsuccess = () =>
{
let i, t, r = req.result;
for ( i = 1; i < 10000000; i++ ) t = t + 'This is a string';
r.n = 'p1';
u.put( r );
console.log( r );
};
}); }
function p_2()
{
return new Promise( ( resolve, reject ) =>
{
let T = DB.transaction( [ 'os_1', 'os_2' ], 'readwrite' ),
q = T.objectStore( 'os_1' ),
u = T.objectStore( 'os_2' ),
req;
req = q.get( 1 );
req.onsuccess = () =>
{
let r = req.result;
r.n = 'p2';
u.put( r );
console.log( r );
};
}); }