2015-02-23 40 views
16

我有一個函數返回一個承諾的庫。我需要多次運行此函數,但每次迭代都必須等到上一個任務完成。你如何同步解決一系列es6承諾?

我的假設是,我可以這樣做:

promiseReturner(1) 
    .then(promiseReturner(2) 
    .then(promiseReturner(3) 
    .then(...) 

這可以用一個循環被簡化:

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    p = p.then(promiseReturner(i)); 
} 

然而,當我在鏈這個每個承諾在執行同時,而不是像.then()似乎意味着一個接一個。很明顯,我錯過了一些有關承諾的基礎知識 - 但在閱讀了幾篇教程和博客文章後,我仍然迷失了方向。

Here's a codepen I wrote up to demonstrate my attempt

+1

是否'promiseReturner( n)「回覆承諾或履行承諾 - 返回功能? – Bergi 2015-09-04 10:32:12

回答

21

您的「非循環」解決方案也不適用。你必須一函數傳遞.then,而不是一個承諾:

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    (function(i) { 
     p = p.then(function() { 
      return promiseReturner(i); 
     }); 
    }(i)); 
} 

如果函數返回一個承諾,那麼你得到的鏈式效應。

有關承諾MDN的更多信息。


可與let(和箭頭的功能)可以簡化爲:

var p = Promise.resolve(); 
for (let i=1; i<=10; i++) { 
    p = p.then(() => promiseReturner(i)); 
} 

或者.bind(這是ES5):

var p = Promise.resolve(); 
for (var i=1; i<=10; i++) { 
    p = p.then(promiseReturner.bind(null, i)); 
} 
+2

也許更清楚:「你必須通過一個函數*返回一個承諾*」? – 2015-02-23 21:03:44

+0

沒關係你解釋,後來在 – 2015-02-23 21:04:33

+0

我曾嘗試將它包裝在一個函數中[見這裏](http://codepen.io/anon/pen/zxjExL?editors=001),但它似乎只運行在最後諾言。爲什麼封裝將其封鎖在自調用函數中似乎解決了這個問題? – 2015-02-23 21:16:16

1

可以使用ES6發電機和圖書館使用async/awaitco

co(function*() { 
    while(upto < 10) { 
    var result = yield Promise.resolve(true); 
    } 
    return result; 
}).then(function (value) { 
    console.log(value); 
}, function (err) { 
    console.error(err.stack); 
}); 

這裏的一些細節是如何工作的:http://davidwalsh.name/async-generators

1

這裏是我用來解決同樣的問題的解決方案:

var recursiveFunction = function(values) { 
    return new Promise(function(resolve, reject) { 
    if (values.length <= 0) { 
     return resolve(); 
    } else { 
     return promiseReturner(values[0]).then(function() { 
      values.shift(); 
      return recursiveFunction(values).then(function() { 
       resolve(); 
      }); 
     }); 
     } 
    }); 
} 

recursiveFunction([1,2]).then(function(r) { 
console.warn('Finished solving promises sequentially'); 
}) 
0

如果您正在使用ES6,就可以實現這一點使用array.reduce 。我覺得很整齊。

const functions = [/* array of functions which return promises */]; 
const finalPromise = functions.reduce(async (promise, asyncFn) => { 
    await promise; 
    return asyncFn(); 
}, Promise.resolve()); 
-1

您可以通過nsynjs運行你的代碼,它會停留在返回承諾每個函數的執行,並且將一直等到承諾解決:

var promiseReturner = function(i) { 
 
    return new Promise(function(resolve, reject) { 
 
     setTimeout(function(){ 
 
      resolve("result is "+i) 
 
     }, 1000); 
 
    }); 
 
}; 
 

 
function synchronousCode() { 
 
    for (var i=1; i<=10; i++) { 
 
     var p=promiseReturner(i); // nsynjs will pause here until promise is resolved 
 
     console.log(p.data); // `data` will contain result of the promise 
 
    } 
 
}; 
 
\t 
 
nsynjs.run(synchronousCode, null, function(){ 
 
\t console.log("finish"); 
 
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>