簡體   English   中英

如何連續執行承諾?

[英]How to execute promises in series?

var promiseReturningFuncs = [];
for(var i = 0; i < 5; i++){
  promiseReturningFuncs.push(askQuestion);
}

var programmers = [];
Promise.reduce(promiseReturningFuncs, function(resp, x) {
  console.log(typeof resp);
  if(typeof resp != "function") {
    programmers.push(resp);
  }
  return x();
})
.then(function(resp) {
  programmers.push(resp);
  console.log(programmers);
});

我的目標:依次執行askQuestion函數並解析該函數​​創建的對象數組。 (此功能必須按順序執行,以便可以響應用戶輸入)

想象一下,askQuestion函數返回一個可以解析我要添加到數組中的對象的promise。

這是我的雜亂方式。 我正在尋找找到一種更清潔的方法,理想情況下,我什至不需要推送到數組,而只有一個最終的.then,其中響應是一個數組。

由於您似乎正在使用Bluebird Promise庫,因此有許多內置選項可用於對Promise返回函數進行排序。 您可以使用Promise.reduce()Promise.map()並發值為1, Promise.mapSeriesPromise.each() 如果迭代器函數返回了一個Promise,則所有這些都將等待下一次迭代,直到該Promise得以解決。 使用哪種方法更多地取決於數據的結構方式和所需的結果(實際上都不顯示或描述的結果)。

假設您有一系列的promise返回函數,並且想一次調用它們,等待一個函數解析后再調用下一個。 如果您想要所有結果,那么我建議Promise.mapSeries()

let arrayOfPromiseReturningFunctions = [...];

// call all the promise returning functions in the array, one at a time
// wait for one to resolve before calling the next
Promise.mapSeries(arrayOfPromiseReturningFunctions, function(fn) {
    return fn();
}).then(function(results) {
     // results is an array of resolved results from all the promises
}).catch(function(err) {
     // process error here
});

也可以使用Promise.reduce() ,但它會累加一個結果,將結果從一個傳遞到下一個,並以一個最終結果結束(就像Array.prototype.reduce()一樣)。

Promise.map()是一個更普遍的版本Promise.mapSeries()可以讓你控制並發數(在飛行異步操作的同時數)。

Promise.each()還將對您的函數進行排序,但不會累加結果。 它假定您沒有結果,或者您正在帶外或通過副作用累積結果。 我傾向於不喜歡使用Promise.each()因為我不喜歡副作用編程。

您可以使用ES6(ES2015)功能在純JS中解決此問題:

function processArray(arr, fn) {
    return arr.reduce(
        (p, v) => p.then((a) => fn(v).then(r => a.concat([r]))),
        Promise.resolve([])
    );
}

它將給定數組的函數應用於序列,並解析為結果數組

用法:

const numbers = [0, 4, 20, 100];
const multiplyBy3 = (x) => new Promise(res => res(x * 3));

// Prints [ 0, 12, 60, 300 ]
processArray(numbers, multiplyBy3).then(console.log);

您將要仔細檢查瀏覽器的兼容性,但這適用於相當當前的Chrome(v59),NodeJS(v8.1.2)以及大多數其他瀏覽器。

使用遞歸函數(以非承諾方式)一個接一個地執行:

(function iterate(i,result,callback){
 if( i>5 ) callback(result);askQuestion().then(res=>iterate(i+1,result.concat([res]),callback);
})(0,[],console.log);

出於保證,可以將其包裝在承諾中:

function askFive(){
return new Promise(function(callback){
(function iterate(i,result){
 if( i>5 ) callback(result);askQuestion().then(res=>iterate(i+1,result.concat([res]),callback);
})(0,[],console.log);
});
}

askFive().then(console.log);

要么:

function afteranother(i,promise){
   return new Promise(function(resolve){
     if(!i) return resolve([]);
     afteranother(i-1,promise).then(val=>promise().then(val2=>resolve(val.concat([val2])));
   });
}

afteranother(5,askQuestion).then(console.log);

您可以使用遞歸,以便可以在then塊中移至下一個迭代。

function promiseToExecuteAllInOrder(promiseReturningFunctions /* array of functions */) {
  var resolvedValues = [];

  return new Promise(function(resolve, reject) {
    function executeNextFunction() {
      var nextFunction = promiseReturningFunctions.pop();
      if(nextFunction) {
        nextFunction().then(function(result) {
          resolvedValues.push(result);
          executeNextFunction();
        });
      } else {
        resolve(resolvedValues);
      }
    }
    executeNextFunction();
  }
}

暫無
暫無

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

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