Dans le processus de développement quotidien, vous pouvez rencontrer des scénarios de contrôle de concurrence, tels que le contrôle du nombre de requêtes simultanées. Alors, comment implémenter le contrôle de concurrence en JavaScript ? Avant de répondre à cette question, introduisons brièvement le contrôle de concurrence.
Supposons qu'il y ait 6 tâches à effectuer à exécuter et que nous souhaitions limiter le nombre de tâches pouvant être exécutées en même temps, c'est-à-dire qu'au plus 2 tâches peuvent être exécutées en même temps . Lorsqu'une tâche de la Liste des tâches d'exécution est terminée, le programme obtiendra automatiquement une nouvelle tâche à faire à partir de la Liste des tâches à faire et ajoutera la tâche à Exécution liste de tâches . Afin de permettre à chacun de comprendre le processus ci-dessus de manière plus intuitive, Abago a spécialement dessiné les 3 images suivantes :
D'accord , après avoir introduit le contrôle de concurrence, Brother Abao utilisera la bibliothèque async-pool sur Github pour introduire l'implémentation spécifique du contrôle de concurrence des tâches asynchrones.
async-pool : https://github.com/rxaviers/async-pool
Exécutez plusieurs fonctions de retour de promesse et asynchrones avec une concurrence limitée à l'aide d'ES6/ natif ES7.
async-pool Cette bibliothèque fournit deux versions différentes d'implémentation, ES7 et ES6 après les avoir analysées avant. l'implémentation spécifique, voyons comment l'utiliser.
const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i)); await asyncPool(2, [1000, 5000, 3000, 2000], timeout);
Dans le code ci-dessus, nous utilisons la fonction async-pool fournie par cette bibliothèque pour implémenter la concurrence asynchrone des tâches contrôle. asyncPool
La signature de la fonction est la suivante : asyncPool
function asyncPool(poolLimit, array, iteratorFn){ ... }
poolLimit
array
iteratorFn
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
En observant les informations d'annotation ci-dessus, nous pouvons approximativement comprendre le contrôle circuler à l'intérieur de la fonction . Analysons d'abord l'implémentation ES7 de la fonction . asyncPool
asyncPool
2.2 Implémentation d'asyncPool ES7
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); }
, combinées à la fonctionnalité Promise.all
fournie dans ES7, et enfin Implémentation de la fonction de contrôle de concurrence. À l'aide de la ligne d'instruction Promise.race
, nous attendrons que la tâche la plus rapide de la async await
liste des tâches d'exécutionawait Promise.race(executing);
se termine avant de continuer à exécuter la boucle suivante. La mise en œuvre d'asyncPool ES7 est relativement simple. Voyons ensuite comment obtenir la même fonction sans utiliser la fonctionnalité
async await
2.3 Implémentation d'asyncPool ES6
function asyncPool(poolLimit, array, iteratorFn) { let i = 0; const ret = []; // 存储所有的异步任务 const executing = []; // 存储正在执行的异步任务 const enqueue = function () { if (i === array.length) { return Promise.resolve(); } const item = array[i++]; // 获取新的任务项 const p = Promise.resolve().then(() => iteratorFn(item, array)); ret.push(p); let r = Promise.resolve(); // 当poolLimit值小于或等于总任务个数时,进行并发控制 if (poolLimit <= array.length) { // 当任务完成后,从正在执行的任务数组中移除已完成的任务 const e = p.then(() => executing.splice(executing.indexOf(e), 1)); executing.push(e); if (executing.length >= poolLimit) { r = Promise.race(executing); } } // 正在执行任务列表 中较快的任务执行完成之后,才会从array数组中获取新的待办任务 return r.then(() => enqueue()); }; return enqueue().then(() => Promise.all(ret)); }
renvoyé par enqueue
sera terminé, la fonction Promise.race(executing)
sera appelée pour obtenir une nouvelle tâche à faire à partir du tableau Promise
. enqueue
array
3. Frère Abao a quelque chose à dire
et asyncPool
. Parmi eux, l'écriture manuscrite Promise.all
est une question d'entretien courante. Profitant de cette opportunité, frère A Bao a rejoint tout le monde dans l'écriture manuscrite de versions simples des fonctions Promise.race
et Promise.all
. Promise.all
Promise.all(iterable)
方法会返回一个 promise 对象,当输入的所有 promise 对象的状态都变成 resolved
时,返回的 promise 对象就会以数组的形式,返回每个 promise 对象 resolve 后的结果。当输入的任何一个 promise 对象状态变成 rejected
时,则返回的 promise 对象会 reject 对应的错误信息。
Promise.all = function (iterators) { return new Promise((resolve, reject) => { if (!iterators || iterators.length === 0) { resolve([]); } else { let count = 0; // 计数器,用于判断所有任务是否执行完成 let result = []; // 结果数组 for (let i = 0; i < iterators.length; i++) { // 考虑到iterators[i]可能是普通对象,则统一包装为Promise对象 Promise.resolve(iterators[i]).then( (data) => { result[i] = data; // 按顺序保存对应的结果 // 当所有任务都执行完成后,再统一返回结果 if (++count === iterators.length) { resolve(result); } }, (err) => { reject(err); // 任何一个Promise对象执行失败,则调用reject()方法 return; } ); } } }); };
需要注意的是对于 Promise.all
的标准实现来说,它的参数是一个可迭代对象,比如 Array、String 或 Set 等。
Promise.race(iterable)
方法会返回一个 promise 对象,一旦迭代器中的某个 promise 对象 resolved 或 rejected,返回的 promise 对象就会 resolve 或 reject 相应的值。
Promise.race = function (iterators) { return new Promise((resolve, reject) => { for (const iter of iterators) { Promise.resolve(iter) .then((res) => { resolve(res); }) .catch((e) => { reject(e); }); } }); };
本文阿宝哥带大家详细分析了 async-pool 异步任务并发控制的具体实现,同时为了让大家能够更好地理解 async-pool 的核心代码。最后阿宝哥还带大家一起手写简易版的 Promise.all
和 Promise.race
函数。其实除了 Promise.all
函数之外,还存在另一个函数 —— Promise.allSettled
,该函数用于解决 Promise.all
存在的问题,感兴趣的小伙伴可以自行研究一下。
更多编程相关知识,请访问:编程视频!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!