Promise.allSettled 中的 Promise 数组的顺序以及创建数据库事务的顺序?

2023-12-29

在下面的代码中,

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 );
          };
    }); }

indexedDB 将按照创建的顺序维护事务的顺序,除非这些事务不重叠(例如,不涉及每个事务涉及的一组存储中的相同存储)。这几乎与您在更高的承诺层做什么无关。

同时,依赖这种行为也许是不明智的,因为它是隐含的并且有点令人困惑。所以也许用承诺来线性化是可以的。唯一的问题是当你需要最大性能时,我怀疑这是否适用。

  • see https://www.w3.org/TR/IndexedDB-2/#transaction-construct https://www.w3.org/TR/IndexedDB-2/#transaction-construct
  • see indexeddb/localforage 读取是否从同步缓冲区解析? https://stackoverflow.com/questions/54956481

此外,承诺在创建时就开始执行。它们只是不一定在那一刻结束,它们最终会结束而不是立即结束。这意味着调用按照您“创建”包装 indexedDB 调用的承诺的顺序发生。这意味着它依赖于您创建交易的顺序。

无论哪个承诺赢得了比赛。无论使用promise.all。

另外,即使 Promise 不按顺序完成,promise.all 也会保留顺序,仅供参考,但不要让它让你失望。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Promise.allSettled 中的 Promise 数组的顺序以及创建数据库事务的顺序? 的相关文章

随机推荐