国产毛多水多高潮高清,久热这里只有精品视频6,国内精品久久久久久久久电影网,国产男同志CHINA69,精品999日本久久久影院,人人妻人人澡人人爽人人精品,亚洲中文无码永久免

JavaScript 任务池-姚记88903APP下载地址

JavaScript 任务池

2026-01-19 06:24:52投稿人:同創(chuàng)娛樂(lè)備用網(wǎng)址入口(荊州)有限公司圍觀163 評(píng)論

JavaScript 任務(wù)池

線程池

在多線程語(yǔ)言中,我們通常不會(huì)隨意的在需要啟動(dòng)線程的時(shí)候去啟動(dòng) ,而是會(huì)選擇創(chuàng)建一個(gè)線程池 。所謂線程池 ,本意其實(shí)就是(不止這些作用,其余作用可以自行查閱) :

  1. 節(jié)省操作系統(tǒng)資源
  2. 限制最大線程數(shù)。

對(duì)于 JavaScript 來(lái)說(shuō) ,雖然不存在“啟動(dòng)線程”這種問(wèn)題 ,但我們還是可以通過(guò)類似的思想 ,來(lái)限制我們做異步操作的數(shù)量。

分析

首先我們需要一個(gè)數(shù)組,用它來(lái)存儲(chǔ)尚未執(zhí)行的任務(wù),每個(gè)任務(wù)都是一個(gè)函數(shù) ,這個(gè)函數(shù)必須要返回一個(gè) Promise 。

type Task = () =>Promise;const tasks: Task[] = [];

其次我們需要一個(gè)方法來(lái)進(jìn)行任務(wù)的添加  。

function addTask(task: Task): void;

最后我們需要一個(gè)函數(shù)來(lái)執(zhí)行我們所有的 task 。

而在這之前,我們還需要定義一個(gè)值 ,來(lái)定義同時(shí)執(zhí)行的異步任務(wù)的最大數(shù)量 。

function execTasks(): void;

實(shí)現(xiàn)

根據(jù)我們的分析,我們可以寫(xiě)下基礎(chǔ)的代碼如下:

interface TaskPool {   addTask(task: Task): void;}type Task = () =>Promise;function newTaskPool(max = 10): TaskPool {   const tasks: Task[] = [];  function addTask(task: Task): void { }  function execTasks(): void { }}

新增任務(wù)非常簡(jiǎn)單 ,我們寫(xiě)出如下代碼填充 addTask。

function addTask(task: Task): void {   tasks.push(task);}

接下來(lái)就是重頭戲。如何實(shí)現(xiàn) execTasks 方法來(lái)限制最大異步任務(wù)數(shù)量呢 ?

首先我們來(lái)明確一點(diǎn),在下面這個(gè)場(chǎng)景中,如果 foo 函數(shù)是異步操作 ,那么是不會(huì)阻塞我們的代碼執(zhí)行的 。

console.log("Before");foo();console.log("After");

那么我們可以這么操作:

  1. 定義一個(gè)變量用來(lái)記錄當(dāng)前的空閑任務(wù)數(shù)量;
  2. 執(zhí)行 execTasks 時(shí) ,會(huì)選取當(dāng)前任務(wù)數(shù)量和空閑任務(wù)數(shù)二者相比較小的一個(gè);
  3. 根據(jù)該值進(jìn)行循環(huán) ,每次循環(huán)彈出 tasks 第一位的任務(wù)進(jìn)行執(zhí)行;
  4. 執(zhí)行前將空閑任務(wù)數(shù) -1 ,執(zhí)行完畢后空閑任務(wù)數(shù) +1,并再次執(zhí)行 execTasks。
let leisure = max;function execTasks(): void {   if (tasks.length === 0) return;  const execTaskNum = Math.min(tasks.length, leisure);  for (let i = 0; i < execTaskNum; i++) {     const task = tasks.shift();    if (!task) continue;    leisure--;    task().finally(() =>{       leisure++;      execTasks();    });  }}

最后我們只剩下了一個(gè)問(wèn)題了,我們?nèi)绾卧?addTask 后執(zhí)行 execTasks,但又不會(huì)讓下面這種情況導(dǎo)致頻繁執(zhí)行 execTasks :

for (let i = 0; i < 100; i++) addTask();

可以利用防抖 + setTimeout(() =>{ },0) 的特性來(lái)完成。

function addTask(task: Task) {   tasks.push(task);  execTasksAfterAdd();}// 這里借用了 lodash 的 debounce 函數(shù)
,具體實(shí)現(xiàn)不多說(shuō),可以看我以前的文章:防抖與節(jié)流const execTasksAfterAdd = debounce(execTasks);

完整代碼:

import {  debounce } from "lodash";interface TaskQueue {   addTask: (task: () =>Promise) =>void;}function newTaskQueue(maxTaskNum = 10): TaskQueue {   let _leisure = maxTaskNum;  const _tasks: Array<() =>Promise>= [];  function addTask(task: () =>Promise) {     _tasks.push(task);    execAfterTask();  }  const execAfterTask = debounce(execTasks);  function execTasks() {     if (_tasks.length === 0) return;    const execTaskNum = Math.min(_tasks.length, _leisure);    for (let i = 0; i < execTaskNum; i++) {       const task = _tasks.shift();      if (!task) continue;      _leisure--;      task().finally(() =>{         _leisure++;        execTasks();      });    }  }  return {  addTask };}const queue = newTaskQueue(5);for (let i = 0; i < 10; i++) {   queue.addTask(function () {     return new Promise((resolve) =>{       setTimeout(() =>resolve(), 800);    });  });}

使用場(chǎng)景

其實(shí)這種做法的使用場(chǎng)景是比較少的