与本地承诺循环;

我试图做一个asynchronous循环与本地ES6承诺 这种作品,但不正确的。 我想我在某个地方犯了一个大错,我需要有人告诉我它在哪里以及它是如何正确完成的

var i = 0; //creates sample resolver function payloadGenerator(){ return function(resolve) { setTimeout(function(){ i++; resolve(); }, 300) } } // creates resolver that fulfills the promise if condition is false, otherwise rejects the promise. // Used only for routing purpose function controller(condition){ return function(resolve, reject) { console.log('i =', i); condition ? reject('fin') : resolve(); } } // creates resolver that ties payload and controller together // When controller rejects its promise, main fulfills its thus exiting the loop function main(){ return function(resolve, reject) { return new Promise(payloadGenerator()) .then(function(){ return new Promise(controller(i>6)) }) .then(main(),function (err) { console.log(err); resolve(err) }) .catch(function (err) { console.log(err , 'caught'); resolve(err) }) } } new Promise(main()) .catch(function(err){ console.log('caught', err); }) .then(function(){ console.log('exit'); process.exit() }); 

现在输出:

 /usr/local/bin/iojs test.js i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 fin error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] error: [TypeError: undefined is not a function] caught [TypeError: undefined is not a function] exit Process finished with exit code 0 

好的部分:它到达最后。

不好的部分:它捕捉到一些错误,我不知道为什么。

任何带有promise循环的helper函数我已经看到,实际上它比使用recursion开箱即可做得更差。

这是一个更好的.thenReturn但耶:

 function readFile(index) { return new Promise(function(resolve) { setTimeout(function() { console.log("Read file number " + (index +1)); resolve(); }, 500); }); } // The loop initialization Promise.resolve(0).then(function loop(i) { // The loop check if (i < len) { // The post iteration increment return readFile(i).thenReturn(i + 1).then(loop); } }).then(function() { console.log("done"); }).catch(function(e) { console.log("error", e); }); 

在jsfiddle中查看http://jsfiddle.net/fd1wc1ra/

这几乎完全等同于:

 try { for (var i = 0; i < len; ++i) { readFile(i); } console.log("done"); } catch (e) { console.log("error", e); } 

如果你想做嵌套循环,它是完全一样的:

http://jsfiddle.net/fd1wc1ra/1/

 function printItem(item) { return new Promise(function(resolve) { setTimeout(function() { console.log("Item " + item); resolve(); }, 500); }); } var mdArray = [[1,2], [3,4], [5,6]]; Promise.resolve(0).then(function loop(i) { if (i < mdArray.length) { var array = mdArray[i]; return Promise.resolve(0).then(function innerLoop(j) { if (j < array.length) { var item = array[j]; return printItem(item).thenReturn(j + 1).then(innerLoop); } }).thenReturn(i + 1).then(loop); } }).then(function() { console.log("done"); }).catch(function(e) { console.log("error", e); }); 

如果你所要做的只是承诺7,那么这将做到这一点:

 function f(p, i) { return p.then(function() { return new Promise(function(r) { return setTimeout(r, 300); }); }) .then(function() { console.log(i); }); } var p = Promise.resolve(); for (var i = 0; i < 8; i++) { p = f(p, i); } p.then(function() { console.log('fin'); }) .catch(function(e) { console.log(e.message); }); 

循环承诺是很难的,因为几乎不可能陷入循环陷阱中的 JavaScript 闭包 ,但这是可行的。 上面的工作是因为它将.then()全部用​​于循环的子函数f (即远离循环)。

我使用的一个更安全的解决scheme是完全放弃循环,找出像forEach这样的模式,并尽可能地reduce它们,因为它们有效地强制了你的子function:

 [0,1,2,3,4,5,6,7].reduce(f, Promise.resolve()) .then(function() { console.log('fin'); }) .catch(function(e) { console.log(e.message); }); 

这里f是和上面相同的function。 试试吧 。

更新: 在ES6中,你也可以使用for (let i = 0; i < 8; i++)来避免在代码中插入子函数f中的“闭环”陷阱。

PS:你的例子中的错误是.then(main(),它需要是.then(function() { return new Promise(main()); },但是,我认为你使用的模式错误main()应该返回一个promise,而不是被一个包装。

在捕获承诺错误时,尝试loggingerr.stack而不是错误。

在这种情况下,在初始迭代完成之后,它看起来像在从main返回的匿名函数中没有定义resolvereject 。 我不能完全按照你的控制stream程,但这似乎是有道理的 – 在7次迭代完成后,不应再有任何新的承诺。 但是,似乎代码仍然试图运行,就像有更多的承诺要解决。

编辑:这是问题。然后.then(main(),function (err) { 。调用自己的main将导致resolvereject匿名函数内部是未定义的。从我读的方式, main只能被调用为Promise构造函数的一个参数。

我有类似的需求,并尝试接受的答案,但我在操作的顺序有问题。 Promise.all是解决scheme。

 function work(context) { return new Promise((resolve, reject) => { operation(context) .then(result => resolve(result) .catch(err => reject(err)); }); } Promise .all(arrayOfContext.map(context => work(context))) .then(results => console.log(results)) .catch(err => console.error(err)); 

我已经四处寻找各种解决scheme,找不到满意的,所以我最终创造了我自己的。 在这种情况下,对其他人有用:

这个想法是创build一个承诺发电机的数组,并给这个数组一个接一个执行承诺的帮助函数。

在我的情况下,辅助函数就是这样的:

 function promiseChain(chain) { let output = new Promise((resolve, reject) => { resolve(); }); for (let i = 0; i < chain.length; i++) { let f = chain[i]; output = output.then(f); } return output; } 

然后,例如,要一个接一个地加载多个URL,代码将如下所示:

 // First build the array of promise generators: let urls = [......]; let chain = []; for (let i = 0; i < urls.length; i++) { chain.push(() => { return fetch(urls[i]); }); } // Then execute the promises one after another: promiseChain(chain).then(() => { console.info('All done'); }); 

这种方法的优点是它创build的代码相对于常规的for循环来说相当接近,而且缩进量最小。