Promise.allSettled中的promise数组的顺序以及创建数据库事务的顺序? [英] Order of promise array in Promise.allSettled and order in which database transactions are created?

查看:130
本文介绍了Promise.allSettled中的promise数组的顺序以及创建数据库事务的顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中,

Promise.allSettled( [ entry_save(), save_state(), get_HTML() ] ).then( ... );

承诺entry_savesave_state都是readwrite数据库事务,而get_HTMLreadonly.这两个readwrite事务可以合并在一起,但这会使维护的撤消/重做链变得复杂,并且将两个事务的成功和回滚联系在一起,这是不希望的.

entry_save事务需要在save_state事务之前写入.在将entry_save移到Promise.allSettled之前,它是这样工作的,因为entry_save事务是在其他事务之前创建的.这篇 MDN文章解释了如何执行请求的顺序基于何时创建交易而与发出请求的顺序无关.

我的问题是,每个promise过程的同步代码是否都按照其在数组中的放置顺序进行排序,因此,首先放置entry_save将始终导致其事务首先被创建,并保证将执行其数据库请求首先?

尽管它可以运行并且足够快,但我不希望这样做:

entry_save().then( () => { Promise.allSettled( [ save_state(), get_HTML() ] ) } ).then( ... );

如果很重要,那不完全是它的编写方式,它更符合:

entry_save().then( intermediate );,其中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.

如果entry_save创建trans1save_state创建trans2,并且都在函数的同步代码中,这意味着不在数据库请求的onsuccessonerror处理程序之内,或者类似的内容, MDN示例不成立吗?

因此,@ jfriend00写入的位置

这些函数按照它们在数组中的放置顺序进行调用, 但这仅决定了异步的顺序 开始.

由于事务是在异步开始之前在同步代码中创建的,因此此命令将按事务创建的时间顺序来排序写请求的时间吗?

我想测试一下,但不确定如何.如果在Promise.allSettled中使用了两个几乎相同的Promise,如何延迟第一个创建的事务的写请求,使其在第二个创建的事务的写请求之后发生,以测试是否将其首先写入? setTimeout应该终止事务.可能在请求之前放置了一个长时间运行的同步循环.


此问题末尾的代码可以更好地更准确地说明我尝试提出的问题.它以上面引用的文章中的MDN示例为例,并将其分布在放置在Promise.allSettled中的两个诺言中,这两个诺言都试图从get请求的onsuccess事件内写入同一对象存储.

问题是在创建第二个事务之前写的第一个事务中的文章将采用相同的原理,而不论发出请求的顺序如何,仍然保留在此设置中.由于promise的同步部分将按照promise放置在数组中的顺序进行处理,因此promise p_1中的事务将在p_2之前创建.但是,p_1get请求的onsuccess事件中的put请求由于循环建立一个大字符串而被延迟.问题是p_1还会在p_2之前写吗?

在尝试此操作时,我无法让p_2p_1之前写.因此,似乎MDN示例甚至适用于这种类型的设置.但是,我不确定为什么,因为我不了解JS代码是如何真正解释/处理的.

例如,为什么在发出请求后可以定义req.onsuccess函数?我曾经问过问题但仍然不太了解,以确保它不会影响我在此处添加延迟的方式.我知道反之亦然.但我的意思是,我不确定在p_1中发出放置请求之前浏览器如何处理该同步循环,以确保确实知道此示例演示了该设置中始终包含的MDN文章.但是,我发现随着循环迭代次数的增加,请求完成所需的时间会更长.而且,在我观察到的所有情况下,p_1总是在p_2之前写入. p_2p_1之前写入的唯一方法是,如果p_1根本不写,因为该字符串占用了大量内存,导致p_1中的事务被中止.

话虽如此,然后再回到我关于Promise.allSettled数组中的三个承诺的问题的完整设置中,与要求entry_save在剩下的两个承诺上开始Promise.allSettled之前完成Promise.allSettled相比,由于不确定的原因,我的项目的完整代码比后者更快,也就是说,等待entry_save完成比将其包含在Promise.allSettled中要快.

我原本以为反过来.在这一点上,我能想到的唯一原因是,由于entry_savesave_state都正在写入同一对象存储库,因此浏览器所做的任何事情等同于锁定对象存储库直到第一个事务,这就是entry_save完成并删除锁所需的时间比Promise.allSettled开始且不涉及锁之前完成entry_save所需的时间长.我认为只要等待两个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将按创建的顺序维护事务的顺序,除非这些事务不重叠(例如,不涉及同一组存储中的同一存储)每个涉及).无论您在更高的承诺层做什么,这几乎都是如此.

同时,依赖该行为可能是不明智的,因为它是隐式的并且有点混乱.所以也许可以将诺言线性化.唯一的触手可及之处就是您需要最高的性能,我怀疑这是适用的.

此外,promise在创建之时就开始执行.它们只是不一定在那个时候结束,而是最终而不是立即结束.这意味着这些调用按照您创建"包装indexedDB调用的promise的顺序进行.这意味着它取决于您创建交易的顺序.

无论哪个诺言都能赢得比赛.不管使用promise.all.

此外,promise.all会保留订单,即使promise完全失序,也只是为了解决问题,但是不要让它让您失望.

In the following code,

Promise.allSettled( [ entry_save(), save_state(), get_HTML() ] ).then( ... );

promises entry_save and save_state are both readwrite database transactions and get_HTML is readonly. The two readwrite transactions could be combined together but that complicates the undo/redo chain that is maintained and it ties the success and rollback of the two together which is undesired.

The entry_save transaction needs to write before the save_state transaction. Before moving entry_save into the Promise.allSettled that is how it worked because the entry_save transaction was created prior to those of the others. This MDN article explains how the order in which requests are performed is based upon when the transactions are created independently of the order in which the requests are made.

My question is does the synchronous code of each promise process in the order in which it is placed in the array, such that placing entry_save first will always result in its transaction being created first and guaranteeing its database requests will be performed first?

Although it works and is quick enough, I'd prefer to not do this:

entry_save().then( () => { Promise.allSettled( [ save_state(), get_HTML() ] ) } ).then( ... );

If it matters, that's not the exactly the way it is written, it's more consistent with:

entry_save().then( intermediate ); where intermediate invokes the Promise.allSettled.

Thank you.

To clarify a bit, below is the example given in the above cited MDN document.

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 creates trans1 and save_state create trans2, and all in the synchronous code of the functions, meaning not within an onsuccess or onerror handler of a database request or something similar, will the MDN example not hold?

Thus, where @jfriend00 writes,

The functions are called in the order they are placed in the array, but that only determines the order in which the asynchronous are started.

will this order the timing of the write requests by that of the creation of the transactions, since the transactions are created in the synchronous code before the asynchronous can commence?

I'd like to test it but I'm not sure how. If two nearly identical promises are used in a Promise.allSettled, how can the write request of the first created transaction be delayed such that it takes place after the write request of the second created transaction, to test if it will be written first? A setTimeout should terminate the transaction. Perhaps a long-running synchronous loop placed before the request.


The code at the very end of this question may better illustrate more precisely what I have attempted to ask. It takes the MDN example in the article cited above and spreads it across two promises placed in a Promise.allSettled, both of which attempt to write to the same object store from within the onsuccess event of a get request.

The question was will the same principle in the article of the first transaction created writing before the second transaction created, regardless of the order the requests are made, still hold in this set up. Since the synchronous portions of the promises will process in the order the promises are placed in the array, the transaction in promise p_1 will be created before that of p_2. However, the put request in the onsuccess event of the get request in p_1 is delayed by the loop building a large string. The question is will p_1 still write before p_2?

In experimenting with this, I cannot get p_2 to write before p_1. Thus, it appears that the MDN example applies even in this type of set up. However, I cannot be sure of why because I don't understand how the JS code is really interpreted/processed.

For example, why can the req.onsuccess function be defined after the request is made? I asked that question sometime ago but still don't know enough to be sure that it doesn't affect the way I attempted to add in a delay here. I know that it won't work the other way around; but my point is I'm not sure how the browser handles that synchronous loop before the put request is made in p_1 to really know for sure that this example demonstrates that the MDN article ALWAYS holds in this set up. However, I can observe that it takes longer for the requests to complete as the number of loop iterations is increased; and, in all cases I have observed, p_1 always writes before p_2. The only way p_2 writes before p_1 is if p_1 doesn't write at all because of the string taking up to much memory causing the transaction in p_1 to be aborted.

That being said, and returning to the fuller set up of my question concerning three promises in the array of the Promise.allSettled compared to requiring entry_save to complete before commencing a Promise.allSettled on the two remaining promises, in the full code of my project, for reasons I am not sure of, the latter is quicker than the former, that is, waiting for entry_save to complete is quicker than including it in the Promise.allSettled.

I was expecting it to be the other way around. The only reason I can think of at this point is that, since entry_save and save_state are both writing to the same object store, perhaps whatever the browser does equivalent to locking the object store until the first transaction, which is that in entry_save, completes and removing the lock takes longer than requiring that entry_save complete before the Promise.allSettled commences and not involving a lock. I thought that everything would be ready "in advance" just waiting for the two put requests to take place in transaction order. They took place in order but more slowly or at least not as quick as using:

entry_save().then( () => { Promise.allSettled( [ save_state(), get_HTML() ] ) } ).then( ... );

instead of:

 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 will maintain the order of the transactions in order created, except when those transactions do not overlap (e.g. do not involve the same store out of the set of stores each one involves). this is pretty much regardless of what you do at the higher promise layer.

at the same time, maybe it is unwise to rely on that behavior, because it is implicit and a bit confusing. so maybe it is ok to linearize with promises. the only reach catch is when you need maximum performance, which I doubt applies.

moreover, promises begin execution at the time they are created. they just do not necessarily end at that time, they end eventually instead of immediately. that means that the calls happen in the order you 'create' the promises that are wrapping the indexedDB calls. which means that it relies on the order in which you create the transactions.

regardless of which promise wins the race. regardless of using promise.all.

also, promise.all will retain order even if promises complete out of order, just fyi, but do not let that throw you off.

这篇关于Promise.allSettled中的promise数组的顺序以及创建数据库事务的顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆