这个问题很老了,但我们生活在 ES6 和函数式 JavaScript 的世界中,所以让我们看看如何改进。
因为 Promise 会立即执行,所以我们不能只创建一组 Promise,它们都会并行触发。
相反,我们需要创建一个返回Promise的函数数组。然后每个函数将按顺序执行,然后在里面启动Promise。
我们可以通过几种方法解决这个问题,但我最喜欢的方法是使用reduce
.
reduce
与 promises 结合使用会有点棘手,所以我将一个衬垫分解成下面一些更小的易消化的食物。
这个函数的本质是使用reduce
以 的初始值开始Promise.resolve([])
,或者一个包含空数组的Promise。
然后这个Promise将作为 传递到reduce
方法中promise
。这是将每个Promise按顺序链接在一起的关键。下一个要执行的Promise是func
,当then
触发时,将结果连接起来,然后返回该Promise,reduce
并使用下一个Promise函数执行循环。
一旦所有 Promise 都执行完毕,返回的 Promise 将包含每个 Promise 的所有结果的数组。
ES6 示例(一个班轮)
/*
* serial executes Promises sequentially.
* @param {funcs} An array of funcs that return promises.
* @example
* const urls = ['/url1', '/url2', '/url3']
* serial(urls.map(url => () => $.ajax(url)))
* .then(console.log.bind(console))
*/
const serial = funcs =>
funcs.reduce((promise, func) =>
promise.then(result => func().then(Array.prototype.concat.bind(result))), Promise.resolve([]))
ES6 示例(分解)
// broken down to for easier understanding
const concat = list => Array.prototype.concat.bind(list)
const promiseConcat = f => x => f().then(concat(x))
const promiseReduce = (acc, x) => acc.then(promiseConcat(x))
/*
* serial executes Promises sequentially.
* @param {funcs} An array of funcs that return promises.
* @example
* const urls = ['/url1', '/url2', '/url3']
* serial(urls.map(url => () => $.ajax(url)))
* .then(console.log.bind(console))
*/
const serial = funcs => funcs.reduce(promiseReduce, Promise.resolve([]))
用法:
// first take your work
const urls = ['/url1', '/url2', '/url3', '/url4']
// next convert each item to a function that returns a promise
const funcs = urls.map(url => () => $.ajax(url))
// execute them serially
serial(funcs)
.then(console.log.bind(console))