如何并行运行 Promise 链

我通过 MDN 文档找到了以下代码。


var resolveAfter2Seconds = function() {

  console.log("starting slow promise");

  return new Promise(resolve => {

    setTimeout(function() {

      resolve(20);

      console.log("slow promise is done");

    }, 2000);

  });

};


var resolveAfter1Second = function() {

  console.log("starting fast promise");

  return new Promise(resolve => {

    setTimeout(function() {

      resolve(10);

      console.log("fast promise is done");

    }, 1000);

  });

};


var parallel = function() {

  console.log('==PARALLEL with Promise.then==');

  resolveAfter2Seconds().then((message)=>console.log(message));

  resolveAfter1Second().then((message)=>console.log(message));

}

作为执行的结果,我认为每个 Promise 都将是没有顺序保证的并行执行。


但是我写了下面的代码,似乎可以保证顺序。


const promiseFunction1 = () => {

    return new Promise((resolve) => {

        let result = 0;


        for (let i = 0; i < 1000000000; i++) {

            result += 1;

        }

        resolve(result);

    })

}


const promiseFunction2 = () => {

    return new Promise((resolve) => {

        let result = 0;


        for (let i = 0; i < 10; i++) {

            result += 1;

        }

        resolve(result);

    })

}


const parallel = () => {

    promiseFunction1()

        .then(res => console.log(res));

    promiseFunction2()

        .then(res => console.log(res));

}

这两个代码有什么区别?


泛舟湖上清波郎朗
浏览 228回答 2
2回答

小怪兽爱吃肉

Promise 构造函数是完全同步的(除非你调用其他异步的东西,比如setTimeout或另一个 Promise)。在第二个代码中,同步promiseFunction1运行并立即调用resolve。对promiseFunction2.&nbsp;因此,创建的第一个 Promise(这里是 from&nbsp;promiseFunction1)将在第二个之前解决,无论每个promiseFunction运行的同步操作可能是昂贵的。该promiseFunction1承诺立即首先解析,如此这般到microtask队列第一,那么其相关的.then运行第一。昂贵的同步代码通常不是在主线程上运行的好主意,因为它会阻塞 UI - 如果您遇到这种情况,请考虑将其移至工作线程,如果可能的话。对于您的第一个代码:我当时认为每个承诺都是没有顺序保证的并行执行。因为resolveAfter2Seconds2 秒后resolveAfter1Second解析,1 秒后解析,所以几乎可以保证 1 秒 Promise 将首先解析。下面的两个代码是一样的吗?一点也不。首先,promiseFunction当parallel被调用时,两者都会立即运行。在第二种情况下,promiseFunction2仅在promiseFunction1解决后运行。

吃鸡游戏

说Promise链通常意味着一系列then()调用,明确地意图按顺序运行它们,但是以异步方式,等待步骤之间的某些事件。而不是编写一系列深入的嵌套回调......function delay2s(callback){&nbsp; setTimeout(callback,2000);}delay2s(()=>{&nbsp; log.innerText="1.";&nbsp; delay2s(()=>{&nbsp; &nbsp; log.innerText+=" 2.";&nbsp; &nbsp; delay2s(()=>{&nbsp; &nbsp; &nbsp; log.innerText+=" 3.";&nbsp; &nbsp; &nbsp; delay2s(()=>{&nbsp; &nbsp; &nbsp; &nbsp; log.innerText+=" 4.";&nbsp; &nbsp; &nbsp; &nbsp; delay2s(()=>{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.innerText+=" 5.";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay2s(()=>{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.innerText+=" and Done.";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; });&nbsp; });});<span id="log">Soon</span>...你可以保持在一个“理智”的水平:function delay2s(){&nbsp; return new Promise(resolve=>setTimeout(()=>resolve(),2000));}delay2s().then(()=>{&nbsp; log.innerText="1.";&nbsp; return delay2s();}).then(()=>{&nbsp; log.innerText+=" 2.";&nbsp; return delay2s();}).then(()=>{&nbsp; log.innerText+=" 3.";&nbsp; return delay2s();}).then(()=>{&nbsp; log.innerText+=" 4.";&nbsp; return delay2s();}).then(()=>{&nbsp; log.innerText+=" 5.";&nbsp; return delay2s();}).then(()=>{&nbsp; log.innerText+=" and Done.";});<span id="log">Soon</span>而且拥有多个独立的Promises并不代表它们一起运行,而是它们一起等待。当然,这种情况下也有一些不错的辅助工具。就像等待一些事件,并在所有事件都完成后做某事可能看起来像一些讨厌的、命名的回调加上一些更讨厌的计数器:let counter=5;function tryfinal(){&nbsp; if(--counter>0)return;&nbsp; log.innerText+=" all Done.";}for(let i=0;i<counter;i++){&nbsp; setTimeout(()=>{&nbsp; &nbsp; log.innerText=(log.innerText=="Soon"?"":log.innerText+" ")+(i+1)+".";&nbsp; &nbsp; tryfinal();&nbsp; },4000*Math.random());}<span id="log">Soon</span>或者它可以使用Promise.all/Settled():let promises=[];for(let i=0;i<5;i++){&nbsp; promises.push(new Promise(resolve=>setTimeout(()=>{&nbsp; &nbsp; log.innerText=(log.innerText=="Soon"?"":log.innerText+" ")+(i+1)+".";&nbsp; &nbsp; resolve();&nbsp; },4000*Math.random())));}Promise.all(promises).then(()=>log.innerText+=" and Done.");<span id="log">Soon</span>如果你想积极地并行做一些事情,你需要线程,这意味着web workers。此示例在两个线程上向上计数几秒钟,不时报告进度(在此期间它与 CPU 一起烹饪,您可以检查您所在操作系统的一些性能监控应用程序):let limit=5000000000;let report=100000000;if(limit>Number.MAX_SAFE_INTEGER)&nbsp; log.innerText="No, you do not want that.";else {&nbsp; let workertext="data:text/plain,"&nbsp; &nbsp; &nbsp; +escape("for(let i=0;i<="+limit+";i++)"&nbsp; &nbsp; &nbsp; +"&nbsp; if(i%"+report+"===0)"&nbsp; &nbsp; &nbsp; +"&nbsp; &nbsp; postMessage(i);"&nbsp; &nbsp; &nbsp; +"postMessage('Done');");&nbsp; console.log(workertext);&nbsp; let w1=new Worker(workertext);&nbsp; let w2=new Worker(workertext);&nbsp; w1.onmessage=m=>log1.innerText+=" "+m.data;&nbsp; w2.onmessage=m=>log2.innerText+=" "+m.data;}<div id="log1">Worker1: </div><div id="log2">Worker2: </div>旁注:有趣的是,在超出带符号的 32 位整数范围(日志中的 2100000000 -> 2200000000,或实际边界为 2147483647 -> 2147483648)后,计数会变慢。至少在我的 Chrome 中。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript