最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node.js 異步任務(wù)協(xié)作方案:7 種實(shí)用方案與真實(shí)項(xiàng)目案例

 更新時(shí)間:2026年04月13日 10:19:46   作者:寶青書(shū)坊  
文章介紹了7種Node.js中處理多個(gè)獨(dú)立異步任務(wù)的方案,包括Promise.all、Promise.allSettled、Promise.race、Promise.any、事件計(jì)數(shù)器、流式處理和隊(duì)列控制,每種方案都適用于特定場(chǎng)景,感興趣的朋友跟隨小編一起看看吧

多個(gè)獨(dú)立異步任務(wù),如何高效協(xié)作?從 Promise.all 到隊(duì)列控制,本文用 7 個(gè)真實(shí)場(chǎng)景給出答案。

在 Node.js 開(kāi)發(fā)中,我們經(jīng)常需要同時(shí)處理多個(gè)獨(dú)立的異步任務(wù):讀取多個(gè)配置文件、調(diào)用多個(gè)外部接口、批量上傳文件……這些任務(wù)彼此獨(dú)立,但最終結(jié)果需要協(xié)同處理。如果只是簡(jiǎn)單地逐個(gè) await,性能會(huì)大打折扣;如果盲目并發(fā),又可能引發(fā)資源耗盡或錯(cuò)誤處理混亂。

本文將介紹 7 種成熟的異步協(xié)作方案,每種都配有真實(shí)項(xiàng)目中的代碼示例,幫助你快速應(yīng)用到實(shí)際工作中。

1.Promise.all—— 應(yīng)用啟動(dòng)加載必要配置

場(chǎng)景:服務(wù)啟動(dòng)時(shí)必須讀取數(shù)據(jù)庫(kù)、Redis 和第三方密鑰三個(gè)配置文件,任何一個(gè)缺失或格式錯(cuò)誤都不能繼續(xù)啟動(dòng)。

const fs = require('fs').promises;
async function loadConfigs() {
  const [db, redis, secrets] = await Promise.all([
    fs.readFile('./config/db.json', 'utf8').then(JSON.parse),
    fs.readFile('./config/redis.json', 'utf8').then(JSON.parse),
    fs.readFile('./config/secrets.json', 'utf8').then(JSON.parse)
  ]);
  console.log('所有配置加載完成', { db, redis, secrets });
}

特點(diǎn):全成功或全失敗,結(jié)果以數(shù)組順序返回。適合“缺一不可”的場(chǎng)景。

2.Promise.allSettled—— 批量同步用戶數(shù)據(jù)到多個(gè)外部系統(tǒng)

場(chǎng)景:用戶更新個(gè)人資料后,需要同步到 CRM、郵件服務(wù)、推送系統(tǒng)。允許個(gè)別失敗,但要記錄失敗原因,后續(xù)重試。

async function syncUserToExternal(user) {
  const tasks = [
    syncToCRM(user),
    syncToEmailService(user),
    syncToPushService(user)
  ];
  const results = await Promise.allSettled(tasks);
  const failed = results.filter(r => r.status === 'rejected');
  if (failed.length) {
    console.error(`同步失敗 ${failed.length} 個(gè)系統(tǒng)`, failed.map(f => f.reason));
    // 將失敗記錄到數(shù)據(jù)庫(kù),等待重試隊(duì)列處理
  }
  return results;
}

特點(diǎn):等待所有任務(wù)完成,無(wú)論成功或失敗,都能拿到每個(gè)任務(wù)的最終狀態(tài)。

3.Promise.race—— HTTP 請(qǐng)求超時(shí)控制

場(chǎng)景:調(diào)用外部 API,必須在 3 秒內(nèi)返回結(jié)果,否則自動(dòng)降級(jí)使用緩存數(shù)據(jù)。

function fetchWithTimeout(url, timeout = 3000) {
  const controller = new AbortController();
  const fetchPromise = fetch(url, { signal: controller.signal });
  const timeoutPromise = new Promise((_, reject) =>
    setTimeout(() => {
      controller.abort();
      reject(new Error('請(qǐng)求超時(shí)'));
    }, timeout)
  );
  return Promise.race([fetchPromise, timeoutPromise]);
}
// 使用
try {
  const data = await fetchWithTimeout('https://slow-api.example.com/data', 3000);
  console.log(data);
} catch (err) {
  console.log('使用緩存數(shù)據(jù)');
}

特點(diǎn):只取最先完成的那個(gè)結(jié)果(成功或失?。?。常用于超時(shí)控制、多源競(jìng)速。

4.Promise.any—— 多 CDN 資源容災(zāi)加載

場(chǎng)景:前端靜態(tài)資源部署在三個(gè) CDN 上,只要任意一個(gè) CDN 返回成功,就使用該資源,忽略失敗的 CDN。

async function loadScriptFromCDNs(urls) {
  const fetchTasks = urls.map(url => fetch(url).then(res => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.text();
  }));
  try {
    const scriptContent = await Promise.any(fetchTasks);
    eval(scriptContent); // 實(shí)際項(xiàng)目中建議使用更安全的方式
    console.log('腳本加載成功');
  } catch (aggregateError) {
    console.error('所有 CDN 均不可用', aggregateError.errors);
  }
}
loadScriptFromCDNs([
  'https://cdn1.example.com/lib.js',
  'https://cdn2.example.com/lib.js',
  'https://cdn3.example.com/lib.js'
]);

特點(diǎn):只要有一個(gè)成功就返回,全部失敗才拋出異常。非常適合冗余容災(zāi)設(shè)計(jì)。

5. 事件計(jì)數(shù)器 —— 舊式多文件寫(xiě)入完成后合并壓縮

場(chǎng)景:維護(hù)一個(gè)老項(xiàng)目(基于回調(diào)風(fēng)格),需要等三個(gè)日志文件全部寫(xiě)入磁盤(pán)后,再執(zhí)行合并壓縮操作。

const EventEmitter = require('events');
const fs = require('fs');
class FileWriter extends EventEmitter {
  writeAndNotify(file, data) {
    fs.writeFile(file, data, (err) => {
      if (err) this.emit('error', err);
      else this.emit('done', file);
    });
  }
}
// 應(yīng)用
const writer = new FileWriter();
let completed = 0;
const total = 3;
function onAllDone() {
  console.log('所有文件寫(xiě)入完成,開(kāi)始合并壓縮');
  // 執(zhí)行合并邏輯
}
writer.on('done', (file) => {
  console.log(`${file} 寫(xiě)入完成`);
  if (++completed === total) onAllDone();
});
writer.writeAndNotify('log1.txt', 'data1');
writer.writeAndNotify('log2.txt', 'data2');
writer.writeAndNotify('log3.txt', 'data3');

特點(diǎn):原始但可控,適合無(wú)法使用 Promise 的舊環(huán)境或需要細(xì)粒度事件監(jiān)聽(tīng)時(shí)使用。

6. 流式處理 —— 實(shí)時(shí)聚合多個(gè)傳感器數(shù)據(jù)流

場(chǎng)景:物聯(lián)網(wǎng)網(wǎng)關(guān)接收溫度、濕度、氣壓三個(gè)傳感器的實(shí)時(shí)數(shù)據(jù)流,需要每收到一組(三個(gè)傳感器各一個(gè)值)就計(jì)算平均值并推送。

const { fromEvent, merge, bufferCount } = require('rxjs');
const { EventEmitter } = require('events');
const sensorA = new EventEmitter();
const sensorB = new EventEmitter();
const sensorC = new EventEmitter();
// 模擬每秒推送一次數(shù)據(jù)
setInterval(() => sensorA.emit('data', Math.random() * 30), 1000);
setInterval(() => sensorB.emit('data', Math.random() * 60), 1000);
setInterval(() => sensorC.emit('data', Math.random() * 10), 1000);
// 將 EventEmitter 轉(zhuǎn)為 Observable
const streamA = fromEvent(sensorA, 'data');
const streamB = fromEvent(sensorB, 'data');
const streamC = fromEvent(sensorC, 'data');
// 合并并每收到3個(gè)值(各一個(gè))計(jì)算一次平均值
merge(streamA, streamB, streamC)
  .pipe(bufferCount(3))
  .subscribe(values => {
    const avg = values.reduce((a, b) => a + b, 0) / values.length;
    console.log(`實(shí)時(shí)平均傳感器值: ${avg.toFixed(2)}`);
  });

特點(diǎn):適合結(jié)果逐步產(chǎn)生、需要實(shí)時(shí)響應(yīng)的場(chǎng)景。RxJS 提供了強(qiáng)大的組合能力。

7. 隊(duì)列控制并發(fā) —— 限制同時(shí)上傳文件的數(shù)量

場(chǎng)景:用戶一次選擇了 100 個(gè)文件上傳到云存儲(chǔ),必須控制同時(shí)上傳的并發(fā)數(shù)為 5,避免網(wǎng)絡(luò)擁塞和服務(wù)器壓力過(guò)大。

const pLimit = require('p-limit');
const fs = require('fs').promises;
const path = require('path');
async function uploadFile(filePath) {
  console.log(`開(kāi)始上傳 ${path.basename(filePath)}`);
  await new Promise(r => setTimeout(r, 1000)); // 模擬上傳
  console.log(`完成上傳 ${path.basename(filePath)}`);
  return filePath;
}
async function uploadAll(filePaths) {
  const limit = pLimit(5); // 最多5個(gè)并發(fā)
  const tasks = filePaths.map(filePath => 
    limit(() => uploadFile(filePath))
  );
  const results = await Promise.all(tasks);
  console.log(`全部上傳完成,共 ${results.length} 個(gè)文件`);
}
// 生成100個(gè)測(cè)試文件路徑
const files = Array.from({ length: 100 }, (_, i) => `/tmp/file${i}.txt`);
uploadAll(files);

特點(diǎn):既保證并發(fā)效率,又避免資源耗盡。配合 Promise.all 可以等待所有任務(wù)完成。

總結(jié):一張表幫你快速選擇

場(chǎng)景推薦方案
所有任務(wù)必須全部成功,結(jié)果一起使用Promise.all
容忍部分失敗,但需要知道每個(gè)任務(wù)的狀態(tài)Promise.allSettled
只取最快結(jié)果(如超時(shí)、多源競(jìng)速)Promise.race
只要有一個(gè)成功即可,忽略失敗Promise.any
舊項(xiàng)目回調(diào)風(fēng)格或需要細(xì)粒度控制事件計(jì)數(shù)器 / EventEmitter
結(jié)果流式輸出、復(fù)雜組合(如傳感器數(shù)據(jù))RxJS / 異步迭代器
大量任務(wù)且需控制并發(fā)數(shù)量隊(duì)列 + p-limit

在實(shí)際項(xiàng)目中,90% 的異步協(xié)作需求都可以用 Promise.all 和 Promise.allSettled 解決。對(duì)于更復(fù)雜的場(chǎng)景,再考慮流式處理或隊(duì)列控制。掌握這些模式,你的 Node.js 異步編程能力將更上一層樓。

到此這篇關(guān)于Node.js 異步任務(wù)協(xié)作方案:7 種實(shí)用方案與真實(shí)項(xiàng)目案例的文章就介紹到這了,更多相關(guān)node.js 異步任務(wù)協(xié)作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Nodejs?http模塊返回內(nèi)容中文亂碼問(wèn)題及解決

    Nodejs?http模塊返回內(nèi)容中文亂碼問(wèn)題及解決

    這篇文章主要介紹了Nodejs?http模塊返回內(nèi)容中文亂碼問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 使用Node.js調(diào)用DeepSeek大模型API的完整實(shí)戰(zhàn)教程

    使用Node.js調(diào)用DeepSeek大模型API的完整實(shí)戰(zhàn)教程

    每個(gè)開(kāi)發(fā)者應(yīng)學(xué)會(huì)調(diào)用大模型API,如如OpenAI SDK已成為事實(shí)標(biāo)準(zhǔn),安全管理APIKey和理解process.env至關(guān)重要,本文從項(xiàng)目初始化Node.js項(xiàng)目到調(diào)用DeepSeekAPI,詳解異步控制與工程化開(kāi)發(fā)流程,需要的朋友可以參考下
    2026-06-06
  • Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記

    Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記

    這篇文章主要介紹了Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記,本文講解了算術(shù)操作符、關(guān)系操作符、邏輯操作符、局部變量與作用域、控制結(jié)構(gòu)等內(nèi)容,需要的朋友可以參考下
    2014-12-12
  • Node.js檢測(cè)端口(port)是否被占用的簡(jiǎn)單示例

    Node.js檢測(cè)端口(port)是否被占用的簡(jiǎn)單示例

    大家有沒(méi)有遇到過(guò)在開(kāi)啟本地服務(wù)時(shí),有這么一種情況:當(dāng)前端口已經(jīng)被另一個(gè)項(xiàng)目使用了,導(dǎo)致服務(wù)開(kāi)啟失敗。那么接下來(lái),我們通過(guò)簡(jiǎn)簡(jiǎn)單單的示例代碼來(lái)檢測(cè)端口是否已經(jīng)被占用。有需要的朋友們可以參考借鑒。
    2016-09-09
  • 詳解nodejs模板引擎制作

    詳解nodejs模板引擎制作

    本篇文章主要介紹了nodejs模板引擎制作 ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • nodejs簡(jiǎn)單抓包工具使用詳解

    nodejs簡(jiǎn)單抓包工具使用詳解

    這篇文章主要介紹了nodejs簡(jiǎn)單抓包工具使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • express如何解決ajax跨域訪問(wèn)session失效問(wèn)題詳解

    express如何解決ajax跨域訪問(wèn)session失效問(wèn)題詳解

    這篇文章主要給大家介紹了關(guān)于express如何解決ajax跨域訪問(wèn)session失效問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 詳解Nodejs之npm&package.json

    詳解Nodejs之npm&package.json

    本篇文章主要介紹了詳解Nodejs之npm&package.json,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Node.js中的HTTP請(qǐng)求與響應(yīng)詳解

    Node.js中的HTTP請(qǐng)求與響應(yīng)詳解

    本文詳細(xì)講解了Node.js中的HTTP請(qǐng)求與響應(yīng),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Nodejs sublime text 3安裝與配置

    Nodejs sublime text 3安裝與配置

    Sublime Text是一個(gè)輕量、簡(jiǎn)潔、高效、跨平臺(tái)的編輯器,方便的配色以及兼容vim快捷鍵等各種優(yōu)點(diǎn)博得了很多前端開(kāi)發(fā)人員的喜愛(ài)!Sublime Text這款程序員必備代碼編輯器,幾乎每位程序員提到Sublime Text都是贊不絕口!它體積小巧,無(wú)需安裝,綠色便攜
    2014-06-06

最新評(píng)論

合阳县| 威信县| 赣榆县| 博乐市| 德清县| 五大连池市| 关岭| 宣武区| 五峰| 海口市| 洛川县| 卫辉市| 汾阳市| 马关县| 当涂县| 大名县| 玛纳斯县| 镇康县| 浮梁县| 唐山市| 丹巴县| 富阳市| 且末县| 莱阳市| 大兴区| 石首市| 长治县| 钟祥市| 玛沁县| 饶河县| 万州区| 深州市| 湖北省| 青神县| 霍城县| 五台县| 无为县| 谷城县| 巴中市| 区。| 方山县|