这个问题很老了,但我们生活在ES6和函数式JavaScript的世界里,所以让我们看看如何改进。
因为承诺会立即执行,所以我们不能只创建一个承诺数组,它们会同时发射。
相反,我们需要创建一个返回承诺的函数数组。然后依次执行每个函数,然后在其中启动promise。
我们可以用几种方法来解决这个问题,但我最喜欢的方法是reduce。
把“减少”和“承诺”结合起来使用有点棘手,所以我把这句话分成了几个易于理解的小部分。
这个函数的本质是使用以promise .resolve([])或包含空数组的promise开头的reduce。
然后,这个承诺将作为承诺传递给reduce方法。这是将每个承诺按顺序连接在一起的关键。要执行的下一个promise是func,当then触发时,结果被连接起来,然后返回该promise,使用下一个promise函数执行reduce循环。
一旦执行了所有的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))