Promise#all vs顺序等待-时间分辨率的差异

时间:2019-01-13 11:09:27

标签: javascript time promise async-await

在以下代码段中,使用promise#all的解决时间有所不同,并依次等待每个promise。我想深入了解发生了什么,因为在处理性能时这似乎是一个警告。

* Edit:添加了另一种没有函数调用的情况,可能我缺少await的工作方式

// Code goes here

window.onload = function() {
  
    let p = new Promise((res, rej) => {
        setTimeout(() => {
            res('p OK')
        }, 5000);
    })
   
    let p2 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p2 OK')
        }, 5000);
    })
    
    let p3 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p3 OK')
        }, 5000);
    })
  
    async function pp() {
        return new Promise((res, rej) => {
            setTimeout(() => {
                res('pp OK');
            }, 5000);
        });
    }
  
    async function a() {
        let out = await Promise.all([p, pp()]);
        return `#a ${out}`;
    }
  
    async function b() {
       let out1 = await p;
       let out2 = await pp();
       return `#b ${out1} ${out2}`;
    }
    
    async function c() {
        let out1 = await p;
        let out2 = await p2;
        let out3 = await p3;
        return `#c ${out1} ${out2} ${out3}`;
    }
  
    let out1 = document.getElementById("out1");
    let out2 = document.getElementById("out2");
    let out32 = document.getElementById("out2");
    const date = new Date().getSeconds();
    a().then(x => console.log(x)).then(() => out1.innerHTML += `finished after ${new Date().getSeconds() - date}s`);
    b().then(x => console.log(x)).then(() => out2.innerHTML += `finished after ${new Date().getSeconds() - date}s`);
    c().then(x => console.log(x)).then(() => out3.innerHTML += `finished after ${new Date().getSeconds() - date}s`);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>

<head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
</head>

<body>
    <p id="out1">
        Promise#all  
    </p>
    <p id="out2">
        Sequential awaits
    </p>
    <p id="out3">
        Sequential awaits without executing fnc
    </p>
</body>

</html>

2 个答案:

答案 0 :(得分:2)

一些要点可以澄清:

  • 传递给new Promise的构造函数回调函数将立即执行 ,这意味着setTimeout延迟在 时刻开始,无论您是否要等待。

  • 因此,由pp2p3创建的超时将在初始化这些变量后立即启动。由于它们都将在5秒钟后超时,因此相应的承诺(pp2p3)将在大约同一时间解决。同样,这是独立,取决于您使用awaitthenPromise.all还是只是忘记了那些承诺而对它们不做任何事情。 p>

  • 相比之下,函数pp只是一个函数。这不是一个承诺。仅当您真正调用该函数时,您才创建一个具有相应超时时间的promise。

  • await使async函数立即返回,并返回承诺。这意味着该函数的其余代码将被推迟,而其他Javascript代码的其余部分将不会被推迟:该函数返回并在该函数调用之后继续执行。当调用堆栈为空时,将处理不同的事件队列。因此它不是阻塞。一旦传递给await的承诺得以解决,就会神奇地发生一些事情:async的函数执行上下文被还原,并且执行继续直到下一个await 。如果没有更多的await要执行,并且函数结束,则返回的承诺(遇到第一个await时)将被解析

    >
  • Promise.all不影响个人承诺的达成时间。它创建了一个新的诺言,当给定的诺言全部解决后,该诺言就会解决。如上所述,您的情况(pp2)中的承诺大约在同一时间解决,因此Promise.all也将在大约5秒钟后解决。

  • 如果您执行await pp(),则仅在此处创建该承诺,然后再创建。并且因为您之前有一个await p,所以执行pp()可能需要5秒钟。因此,相应的超时不会在第二个await执行之前开始。这就是await p; await pp()需要两次5秒才能解决的原因。

  • 您进行await p; await p2时的情况有所不同。那里已经创建了两个promise,并且它们的超时已经开始。因此,当第一个await结束5秒后,JS将到达第二个await并且发现p2也已解决。将没有任何额外的等待时间(异步管理除外,在异步管理中await总是将事件放入微任务队列中)

我认为,使用这些元素,您可以正确地描述代码将如何执行以及如何获得预期的输出。

答案 1 :(得分:0)

在第一个函数中,它立即执行pp以启动承诺超时。 在第二个函数中,它等待p完成后才执行pp以开始承诺超时。

await关键字“阻止*”执行,直到承诺解决为止,然后继续下一行。

RE:更新

在您的第三个示例中,所有的诺言都是在那时开始的。 await关键字等待,直到承诺被解决。因为您的所有诺​​言都是同时开始的,所以它们都将在很小的范围内解决。到您按下await p2时,它可能已经解决。与p3相同。

在第二个示例中,pp直到p完成才开始。

[*]并没有真正阻止执行,但这就是它对您的代码的影响。