这个问题很老了,但我们生活在一个 ES6 和函数式 JavaScript 的世界里,所以让我们看看如何改进。
因为 Promise 会立即执行,所以我们不能只创建一个 Promise 数组,它们都会并行触发。
相反,我们需要创建一个返回 Promise 的函数数组。然后每个函数将按顺序执行,然后在内部启动 Promise。
我们可以通过几种方式解决这个问题,但我最喜欢的方式是使用reduce
.
与 promises 结合使用会有点棘手reduce
,所以我将一个衬里分解为下面一些较小的易消化部分。
此函数的本质是使用reduce
从 的初始值Promise.resolve([])
或包含空数组的 Promise 开始。
然后,此承诺将reduce
作为promise
. 这是将每个承诺按顺序链接在一起的关键。下一个要执行的 Promise 是func
,当then
触发时,结果被连接起来,然后返回该reduce
Promise,使用下一个 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))