簡體   English   中英

JavaScript承諾:按順序執行承諾

[英]JavaScript Promises: Executing Promises Sequentially

為了更清楚地理解承諾,我一直在閱讀一些非常有趣的文章。 我遇到了以下代碼,它完美地用於順序執行promises。 但我無法理解它是如何工作的。

 function doFirstThing(){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(1);
       },1000)
   })
 }

 function doSecondThing(res){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(res + 1);
       },1000)
   })
 }

 function doThirdThing(res){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(res + 2);
       },1000)
   })
 }
 promiseFactories = [doFirstThing, doSecondThing, doThirdThing];

 function executeSequentially(promiseFactories) {
         var result = Promise.resolve(); // this is the most problematic line 
               promiseFactories.forEach(function (promiseFactory) {
               result = result.then(promiseFactory);// what is happening here ?
    });
    return result;
 }

 executeSequentially(promiseFactories)

我確實理解,promises會在創建后立即執行。 由於某種原因,我無法理解執行的流程。 特別是以下這一行:

var result = Promise.resolve()//and empty promise is created.

如果有人可以幫助我理解如何在空承諾的'then'方法中調用promiseFactory方法使它按順序執行,就像這樣。 或者是因為forEach循環?

result = result.then(promiseFactory);

我嘗試用'map'函數替換'forEach',但仍產生相同的結果。 即,順序執行的方法。 另外,值是如何從一個鏈式函數傳遞給另一個?

任何幫助或文章/博客都非常感謝。

如果你想要這樣的行為,總是建議使用Promise.all

 function doFirstThing() { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(1); }, 1000) }) } function doSecondThing(res) { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(res + 1); }, 1000) }) } function doThirdThing(res) { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(res + 2); }, 1000) }) } let promiseFactories = [doFirstThing(2), doSecondThing(1), doThirdThing(3)]; Promise.all(promiseFactories) .then(data => { console.log("completed all promises", data); }) 

要一個接一個地順序運行它:

 function doFirstThing() { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(1); }, 1000) }) } function doSecondThing(res) { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(res + 1); }, 3000) }) } function doThirdThing(res) { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(res + 2); }, 5000) }) } promiseFactories = [doFirstThing, doSecondThing, doThirdThing]; function executeSequentially(promiseFactories) { promiseFactories.forEach(function(promiseFactory) { promiseFactory(1).then((data) => { console.log(data) }); }); } executeSequentially(promiseFactories); 

您可以將Promise映像為內部執行的框。 就創建承諾而言,執行開始。 要獲取結果值,您必須打開該框。 您可以使用then為它:

Promise.resolve(5).then(result => console.log(result)); // prints 5

如果你想鏈接承諾,你可以通過逐個打開框來實現:

Promise.resolve(5)
  .then(result => Promise.resolve(result + 1))
  .then(result => Promise.resolve(result * 2))
  .then(result => console.log(result));  // prints 12

這種鏈接使執行同步 (逐個)。

如果要異步執行多個promise(不鏈接結果),可以使用Promise.all

Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
  .then(result => console.log(result));  // prints [1,2,3]

在你的情況下:

Promise.all(promiseFactories).then(result => console.log(result));

如何使用promises的另一個選擇是await它們:

(async ()=> {
   var res1 = await Promise.resolve(5);
   var res2 = await Promise.resolve(res1 + 1);
   var res3 = await Promise.resolve(res2 * 2);
   console.log(res3); // prints 12
})();

await的工作原理類似於then -它使異步執行,以同步

在你的情況下:

async function executeSequentially(promiseFactories) {
    for (const p of promiseFactories) {
        const result = await p;
        console.log(result);
    } 
}

注意: await將值打包到Promise中:

var res1 = await 5; // same as await Promise.resolve(5)

executeSequentially方法一個接一個地返回所有Promises。 它碰巧迭代在promiseFactory ,但它可以寫成:

function executeSequentially(promiseFactories) {
  return doFirstThing()
  .then(() => doSecondThing())
  .then(doThirdThing() );
}

它是一樣的。 我們基本上回歸了一個承諾。

但是,現在我們要迭代一系列承諾。

在迭代時,我們需要將當前的Promise附加到之前的then forEach不會在每次迭代中暴露下一個Promise - 或前一個Promise。 然而,我們仍然需要它,以便逐一鏈接Promise。 因此, result '黑客':

function executeSequentially(promiseFactories) {
  var result = Promise.resolve(); /*We need a thing that keeps yelling 
  the previous promise in every iteration, so we can keep chaining.
  This 'result' var is that thing. This is keeping a Promise in every
  iteration that resolves when all the previous promises resolve
  sequentially. Since we don't have a Promise in the array
  previous to the first one, we fabricate one out of 'thin air'
  with Promise.resolve() */
  promiseFactories.forEach(function (promiseFactory) {
    result = result.then(promiseFactory); /* Here result is update
    with a new Promise, with is the result of  chaining `result`
    with the current one. Since `result` already had all the previous ones,
    at the end, `result` will be a Promise that depends upon all the
    Promises resolution.*/
  });
return result;
}

現在,還有一個語法怪癖可能令你困惑:

result = result.then(promiseFactory);

這一行幾乎與以下內容相同:

result = result.then(resolvedValue => promiseFactory(resolvedValue));

如果有人可以幫助我理解如何在空承諾的'then'方法中調用promiseFactory方法使它按順序執行,就像這樣。 或者是因為forEach循環?

首先, promiseFactory在那里是一個非常糟糕的名字。 該方法應更好地編寫如下:

function executeSequentially(promises) {
  var result = Promise.resolve(); // this is the most problematic line 
        promises.forEach(function (currentPromise) {
        result = result.then(currentPromise);// what is happening here ?
});
return result;
}

所以:

如何在空承諾的'then'方法中調用currentPromise方法使其順序執行?

它使因為當你通過附加承諾到另一個是順序執行的then ,它依次執行。 then的事情,它是不是在所有相關的事實,我們遍歷承諾。 在迭代之外的普通Promise,它的工作方式幾乎相同:

Promise.resolve() // fake Promises that resolves instanly
.then(fetchUsersFromDatabase) // a function that returns a Promise and takes
// like 1 second. It won't be called until the first one resolves
.then(processUsersData) // another function that takes input from the first, and
// do a lot of complex and asynchronous computations with data from the previous promise.
// it won't be called until `fetchUsersFromDatabase()` resolves, that's what
// `then()` does.
.then(sendDataToClient); // another function that will never be called until
// `processUsersData()` resolves

如果我們布置foreach循環,它將如下所示

 function doFirstThing(){ return new Promise(function(resolve,reject){ setTimeout(()=>{ console.log(1); resolve(1); },1000) }) } function doSecondThing(res){ return new Promise(function(resolve,reject){ setTimeout(()=>{ console.log(2); resolve(res + 1); },2000) }) } function doThirdThing(res){ return new Promise(function(resolve,reject){ setTimeout(()=>{ console.log(3); resolve(res + 2); },3000) }) } Promise.resolve() .then(doFirstThing()) .then(doSecondThing()) .then(doThirdThing()); 

我確實理解,promises會在創建后立即執行。 由於某種原因,我無法理解執行的流程。 特別是以下行: var result = Promise.resolve()//and empty promise is created.

這只是為了掌握承諾鏈的起點。 這是一個已經解決的承諾。 為了更好地理解它,您可以使用您的一個承諾來獲得承諾鏈,如下所示。

let promiseFactories= [doSecondThing, doThirdThing];

let result = doFirstThing();

promiseFactories.forEach(function (promiseFactory) {
     result = result.then(promiseFactory);
});

這也行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM