小程序中如何实现并发控制?(下)
三、asyncPool并发控制的实现async-pool 这个库提供了 ES7 和 ES6 两种不同版本的实现在分析其具体实现之前我们来看一下它如何使用。3.1 asyncPool 的使用function asyncPool(poolLimit, array, iteratorFn){ ... }该函数接收 3 个参数poolLimitNumber表示限制的并发数arrayArray表示任务数组iteratorFnFunction表示迭代函数用于实现对每个任务项进行处理该函数会返回一个 Promise 对象或异步函数。asyncPool在有限的并发池中运行多个promise-returning async functions。一旦其中一个承诺被拒绝它就会立即拒绝。当所有 Promise 完成时它就会resolves。它尽快调用迭代器函数在并发限制下。例如const timeout i new Promise(resolve setTimeout(() resolve(i), i)); await asyncPool(2, [1000, 5000, 3000, 2000], timeout); // Call iterator (i 1000) // Call iterator (i 5000) // Pool limit of 2 reached, wait for the quicker one to complete... // 1000 finishes // Call iterator (i 3000) // Pool limit of 2 reached, wait for the quicker one to complete... // 3000 finishes // Call iterator (i 2000) // Itaration is complete, wait until running ones complete... // 5000 finishes // 2000 finishes // Resolves, results are passed in given array order [1000, 5000, 3000, 2000].通过观察以上的注释信息我们可以大致地了解asyncPool函数内部的控制流程3.2 asyncPool 实现async function asyncPool(poolLimit, array, iteratorFn) { const ret []; // 存储所有的异步任务 const executing []; // 存储正在执行的异步任务 for (const item of array) { // 调用iteratorFn函数创建异步任务 const p Promise.resolve().then(() iteratorFn(item, array)); ret.push(p); // 保存新的异步任务 // 当poolLimit值小于或等于总任务个数时进行并发控制 if (poolLimit array.length) { // 当任务完成后从正在执行的任务数组中移除已完成的任务 const e p.then(() executing.splice(executing.indexOf(e), 1)); executing.push(e); // 保存正在执行的异步任务 if (executing.length poolLimit) { await Promise.race(executing); // 等待较快的任务执行完成 } } } return Promise.all(ret); }在以上代码中充分利用了Promise.all和Promise.race函数特点再结合 ES7 中提供的async await特性最终实现了并发控制的功能。利用await Promise.race(executing);这行语句我们会等待正在执行任务列表中较快的任务执行完成之后才会继续执行下一次循环。四、实践运用使用p-limitconst limitpLimit(5); const fn() { return axios({ method: get, url: https://www.fastmock.site/mock/883c2b5177653e4ef705b7ffdc680af1/daily/story, }) .then(function(response) { return response.data; }); }; const input[]; for(let i0;i50;i) { input.push(limit(fn)) } Promise.all(input).then(res { console.log(res,res) });使用asyncPoolconst fn() { return axios({ method: get, url: https://www.fastmock.site/mock/883c2b5177653e4ef705b7ffdc680af1/daily/story, }) .then(function(response) { return response.data; }); } const input[]; for(let i0;i50;i) { input.push(fn); } const timeout f new Promise(resolve setTimeout(() resolve(f()))); asyncPool(5,input,timeout).then(res { console.log(res,res); })