JavaScript提供了一种收集承诺列表的机制:
const tasks = [ fetch('a'), fetch('b'), fetch('c') ];
const results = await Promise.all(tasks);
但是,如果我想执行所有任务,但只有n
同时执行,该怎么办?
const results = await MorePromise.allWithConcurrency(2, tasks); // 2 at a time
JavaScript是否提供此类功能?如果没有,是否有任何强大的库?
答案 0 :(得分:2)
用纯JS ES6怎么样??
var ps = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), Promise.resolve(4), Promise.resolve(5)],
groupBy = (n,a) => a.reduce((r,p,i) => !(i%n) ? (r.push([p]),r) : (r[r.length-1].push(p),r),[]);
groupBy(2,ps).map(sps => Promise.all(sps).then(console.log));
.as-console-wrapper {
max-height: 100% !important;
}
根据@GrégoryNEUT的正确评论我还有两个选择,以防你有一个数据数组来调用承诺返回函数(我使用bring
模仿fetch
这里)
var bring = (url,data) => new Promise((v,x) => setTimeout(v, ~~(Math.random()*500), data)); // echoes data in 0~500 ms
urls = ["url0", "url1","url2","url3","url4"],
groupBy = (n,a) => a.reduce((r,u,i) => !(i%n) ? (r.push([u]),r) : (r[r.length-1].push(u),r),[]);
groupBy(2,urls).reduce((p,sus,i) => i ? p.then(r => (console.log(`Here I am doing something with the fetched data from urls ${r}`),
Promise.all(sus.map(u => bring(u,u.replace(/[^\d]+/,""))))))
: Promise.all(sus.map(u => bring(u,u.replace(/[^\d]+/,"")))), Promise.resolve())
.then(r => console.log(`Here I am doing something with the fetched data from urls ${r}`), e => console.log(e));
或者使用spread
&的一个小巧时髦的Haskellesque递归方法rest
运算符,例如;
var bring = (url,data) => new Promise((v,x) => setTimeout(v, ~~(Math.random()*500), data)); // echoes data in 0~500 ms
urls = ["url0", "url1","url2","url3","url4"],
groupBy = (n,a) => a.reduce((r,u,i) => !(i%n) ? (r.push([u]),r) : (r[r.length-1].push(u),r),[]),
seqPrms = (sus,...suss) => Promise.all(sus.map(u => bring(u,u.replace(/[^\d]+/,""))))
.then(r => (console.log(`Here I am doing something with the fetched data from urls ${r}`),
suss.length && seqPrms(...suss)),
e => console.log(e));
seqPrms(...groupBy(2,urls));
答案 1 :(得分:0)
您可以使用bluebird
这样的插件来实现它,function允许它:example here
const Promise = require('bluebird');
const _ = require('lodash');
let tasks = [...]; // over 10,000 items.
Promise.all(
_(tasks).map(task => {
return task.doAsyncThing();
})
.value();
);
Promise.map(
tasks,
task => {
return task.doAsyncThing();
},
{ concurrency: 1000 }
);
您也可以自己创建一个能够处理它的功能。这是我自己编写的一个功能,它是可以改进的。
const resultPromises = [];
let nextToCall = 0;
let errorHappened = false;
/**
* Function that get called when one promise got executed
*/
function callbackOnePromiseGotExecuted({
error,
result,
allExecutedCallback,
array,
}) {
resultPromises.push(result);
// Do nothing if an error got reported
if (errorHappened) {
return;
}
// Return the error
if (error) {
allExecutedCallback(null, resultPromises);
errorHappened = true;
return;
}
// Check if it was the last promise to execute
if (resultPromises.length === array.length) {
allExecutedCallback(null, resultPromises);
return;
}
nextToCall += 1;
// Stop if we already acalled everything
if (nextToCall > array.length) return;
// If it wasn't call a new promise
array[nextToCall - 1].call()
.then(ret => callbackOnePromiseGotExecuted({
error: null,
result: ret,
allExecutedCallback,
array,
}))
.catch(e => callbackOnePromiseGotExecuted({
error: e,
result: null,
allExecutedCallback,
array,
}));
}
/**
* Handle the call of multiple promise with concurrency
*/
function promiseWithConcurrencyCallback({
array,
concurrencyNumber,
allExecutedCallback,
}) {
for (let i = 0; i < concurrencyNumber; ++i) {
array[nextToCall].call()
.then(ret => callbackOnePromiseGotExecuted({
error: null,
result: ret,
allExecutedCallback,
array,
}))
.catch(e => callbackOnePromiseGotExecuted({
error: e,
result: null,
allExecutedCallback,
array,
}));
nextToCall += 1;
}
}
function promiseWithConcurrency(array, concurrencyNumber) {
return new Promise((resolve, reject) => {
promiseWithConcurrencyCallback({
array,
concurrencyNumber,
allExecutedCallback: (error, result) => {
if (error) return reject(error);
return resolve(result);
},
});
});
}
const array = [
() => new Promise((resolve) => resolve('01')),
() => new Promise((resolve) => resolve('02')),
() => new Promise((resolve) => resolve('03')),
() => new Promise((resolve) => resolve('04')),
() => new Promise((resolve) => resolve('05')),
() => new Promise((resolve) => resolve('06')),
];
promiseWithConcurrency(array, 2)
.then(rets => console.log('rets', rets))
.catch(error => console.log('error', error));
&#13;
编辑关于我对@Redu帖子的评论
var ps = [new Promise((resolve) => { console.log('A'); setTimeout(() => { resolve(1) }, 5000); }), Promise.resolve(2), Promise.resolve(3), Promise.resolve(4), new Promise((resolve) => { console.log('B'); setTimeout(() => { resolve(5) }, 5000); })],
groupBy = (n,a) => a.reduce((r,p,i) => !(i%n) ? (r.push([p]),r) : (r[r.length-1].push(p),r),[]);
groupBy(2,ps).map(sps => Promise.all(sps).then(console.log));
&#13;
正如您在我编辑过的代码段中看到的那样,console.log('A')
和console.log('B')
会立即显示出来。这意味着函数同时执行,然后每两个解析两次。因此,如果目的是限制对资源的访问权限,那么您的解决方案就不会起作用。他们仍将在同一时间访问。