偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

優(yōu)化 await fetch():性能瓶頸分析與提速方案

開發(fā) 前端
優(yōu)化 await fetch()? 的性能涉及解決多個(gè)瓶頸。從重用連接到切換到高效的流式格式,每個(gè)修復(fù)都對(duì)更快、更高效的網(wǎng)絡(luò)請(qǐng)求做出貢獻(xiàn)??紤]使用 Undici 進(jìn)行更快的請(qǐng)求,避免使用 JSON.stringify() 進(jìn)行不必要的序列化,并實(shí)施并發(fā)控制和緩存等策略,以顯著提高應(yīng)用的性能。

在開發(fā) JavaScript 應(yīng)用程序時(shí),很容易忽視與 fetch() 相關(guān)的性能問題。然而,即使是像 await fetch() 這樣簡(jiǎn)單的代碼,也可能意外地拖慢你的應(yīng)用,導(dǎo)致網(wǎng)絡(luò)請(qǐng)求延遲并讓用戶感到沮喪。在本文中,我們將探討 fetch() 可能導(dǎo)致變慢的原因,并提供解決方案來修復(fù)它。

1. 冷 TCP 連接:突如其來的 200ms 延遲

癥狀:

  • 對(duì) API 的第一個(gè)請(qǐng)求始終比其他請(qǐng)求花費(fèi)更長(zhǎng)時(shí)間。
  • 在執(zhí)行批量操作時(shí),t??(請(qǐng)求時(shí)間的第 95 個(gè)百分位數(shù))急劇飆升。

每個(gè) fetch() 都會(huì)創(chuàng)建一個(gè)新的套接字連接,這涉及:

  • DNS 查詢:將域名解析為 IP 地址。
  • TCP 握手:建立 TCP 連接。
  • TLS 握手:通過 HTTPS 加密連接。

在歐洲等地區(qū),平均往返時(shí)間(RTT)約為 50ms,這意味著每個(gè)新請(qǐng)求都會(huì)花費(fèi)數(shù)百毫秒的額外時(shí)間。

修復(fù)方法:

import { Agent } from'undici';  
const apiAgent = newAgent({  
keepAliveTimeout: 30_000,  
// 保持套接字打開 30 秒  
connections: 100,           // 連接池大小  
});  

constfetchOrders = async () => {  
const response = awaitfetch('https://api.payments.local/v1/orders', {  
    dispatcher: apiAgent  
  });  
return response.json();  
};

在這段代碼中:

  • apiAgent 負(fù)責(zé)管理保持連接。
  • fetchOrders() 函數(shù)使用 undici 通過重用打開的連接高效地獲取數(shù)據(jù)。

2. DNS + TLS:隱藏的瓶頸

即使使用保持連接,對(duì)新域的第一個(gè)請(qǐng)求仍然會(huì)因?yàn)?DNS 查詢和 TLS 握手而變慢。

  • DNS 查詢:阻塞 JavaScript 線程,在移動(dòng)網(wǎng)絡(luò)上可能長(zhǎng)達(dá) 100ms。
  • TLS 握手:涉及三次往返,而 TCP 只需一次。

修復(fù)方法:

  • DNS 緩存:緩存 DNS 查詢以避免重復(fù)查詢。
  • 增加 maxSockets 以處理多個(gè)域。

Nginx 示例:

resolver 9.9.9.9 valid=300s;  
// 緩存 DNS 響應(yīng) 300 秒

Node.js 示例:

const agentWithDnsCache = newAgent({  
connect: { lookup: dnsCache.lookup }, // 使用 DNS 緩存進(jìn)行更快查詢  
});  

constfetchFromNewDomain = async () => {  
const response = awaitfetch('https://newapi.domain.com/v1/data', {  
    dispatcher: agentWithDnsCache,  
  });  
return response.json();  
};

替代方案:QUIC/HTTP-3

為了更快地建立連接,使用支持 0-RTT 的 QUIC/HTTP-3 來繞過這些延遲。

3. response.json() 阻塞事件循環(huán)

當(dāng)服務(wù)器發(fā)送大型 JSON 響應(yīng)(5-10MB 或更大)時(shí),調(diào)用 response.json() 會(huì)阻塞事件循環(huán),消耗 100% 的 CPU。

修復(fù)方法:流式解析

import { parse } from'stream-json'; 
import { chain } from'stream-chain'; 
import { finished } from'stream'; 

conststreamJsonResponse = async (response) => {  
const pipeline = chain([  
    response.body,    // 來自 fetch 的 ReadableStream  
    parse(),          // 解析 JSON 流  
    ({ key, value }) => { /* 處理片段 */ },  
  ]);   

awaitfinished(pipeline);  
};

這段代碼在獲取時(shí)處理 JSON 流,避免了將大量數(shù)據(jù)一次性加載到內(nèi)存中。

4. 優(yōu)化響應(yīng)大小:壓縮和格式

如果網(wǎng)絡(luò)速度正常但加載仍然緩慢,通常是由于數(shù)據(jù)格式低效或缺乏壓縮。

修復(fù)方法:

在客戶端請(qǐng)求壓縮(例如 Brotli):

const fetchDataWithCompression = async (url) => {  
  const response = await fetch(url, {  
    headers: { 'Accept-Encoding': 'br, gzip' },  
  });  
  return response.json();  
};

在 Fastify 后端啟用 Brotli 壓縮:

const fastify = require('fastify')(); 
fastify.register(require('@fastify/compress'), {  
  brotliOptions: { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 } } 
});

Brotli 壓縮相比 Gzip 可以節(jié)省多達(dá) 25% 的空間。

5. 循環(huán)中的 await:并發(fā)殺手

當(dāng)你在循環(huán)中執(zhí)行許多異步任務(wù)時(shí),即使它們可以并發(fā)運(yùn)行,它們也會(huì)按順序執(zhí)行。

常見錯(cuò)誤:

for (const id of ids) {  
  const res = await fetch(`/api/item/${id}`);  
  items.push(await res.json()); 
}

這會(huì)導(dǎo)致請(qǐng)求一個(gè)接一個(gè)地排隊(duì),造成延遲。

修復(fù)方法:限制并發(fā)

const maxConcurrency = 10; // 限制并發(fā)請(qǐng)求數(shù)量  
const requestQueue = [...ids]; // API 請(qǐng)求的 ID 數(shù)組  
const results = [];  

constfetchItemsConcurrently = async () => {  
awaitPromise.all(  
    Array.from({ length: maxConcurrency }, async () => {  
      while (requestQueue.length) {  
        const itemId = requestQueue.pop();  
        const response = awaitfetch(`/api/item/${itemId}`);  
        const itemData = await response.json();  
        results.push(itemData);  
      }  
    })  
  ); 
};

這種方法確保只有有限數(shù)量的請(qǐng)求并發(fā)發(fā)送,防止后端過載。

6. 使用 undici.request 進(jìn)行更快的請(qǐng)求

為了提高性能,考慮使用 undici 的 request 函數(shù)而不是內(nèi)置的 fetch,因?yàn)樗烨覝p少了開銷。

import { request } from'undici'; 

constpostDataWithUndici = async (url, payload) => {  
const { body } = awaitrequest(url, {  
    method: 'POST',  
    body: JSON.stringify(payload),  
    headers: { 'Content-Type': 'application/json' },  
  });  
returnawait body.json(); 
};

7. 通過服務(wù)器配置簡(jiǎn)化 CORS 預(yù)檢

CORS 預(yù)檢請(qǐng)求增加了額外的往返延遲。簡(jiǎn)化請(qǐng)求并緩存預(yù)檢響應(yīng)有助于減少這種開銷。

const express = require('express'); 
const cors = require('cors'); 
const app = express(); 

app.use(cors({  
origin: 'https://your-frontend.com',  
credentials: true,  
maxAge: 86400,  // 緩存預(yù)檢響應(yīng) 24 小時(shí) 
})); 

app.listen(3000, () => {  
console.log('Server running on port 3000'); 
});

8. HTTP/2 中的 HOL 阻塞:大文件上傳影響所有請(qǐng)求

在 HTTP/2 中,大文件上傳可能會(huì)因?yàn)閱?TCP 連接上的多路復(fù)用而阻塞其他請(qǐng)求。為了避免這種情況,應(yīng)將大請(qǐng)求和小請(qǐng)求分開。

const { Agent } = require('undici'); 
const largeUploadAgent = new Agent({ maxStreamsPerConnection: 1 }); 

const uploadLargeFile = async (largeFileUrl, bigFile) => {  
  await fetch(largeFileUrl, { dispatcher: largeUploadAgent, body: bigFile }); 
};

為了獲得更好的性能,使用 HTTP/3,它基于 UDP 工作并避免了 TCP 的瓶頸。

9. 發(fā)送前的 JSON.stringify()

使用 JSON.stringify() 序列化大型負(fù)載會(huì)阻塞事件循環(huán)。相反,使用流式多部分上傳或其他高效的序列化方法。

import { Readable } from'node:stream'; 

conststreamPayload = async (largeData) => {  
const encoder = newTextEncoder();  
const stream = Readable.from(  
    largeData.map(item => encoder.encode(JSON.stringify(item) + '\n'))  
  );  
awaitfetch('/bulk/ingest', { method: 'POST', body: stream }); 
};

這種方法即使在大型數(shù)據(jù)集的情況下也能保持內(nèi)存使用量低。

結(jié)論

優(yōu)化 await fetch() 的性能涉及解決多個(gè)瓶頸。從重用連接到切換到高效的流式格式,每個(gè)修復(fù)都對(duì)更快、更高效的網(wǎng)絡(luò)請(qǐng)求做出貢獻(xiàn)??紤]使用 Undici 進(jìn)行更快的請(qǐng)求,避免使用 JSON.stringify() 進(jìn)行不必要的序列化,并實(shí)施并發(fā)控制和緩存等策略,以顯著提高應(yīng)用的性能。

持續(xù)測(cè)試,定期測(cè)量性能,并考慮使用 GraphQL-over-HTTP/2、gRPC-web 或 msgpack 等替代方案進(jìn)一步優(yōu)化你的應(yīng)用。

原文地址:https://jsdev.space/await-fetch-slow/作者:jsdev

責(zé)任編輯:武曉燕 來源: 前端小石匠
相關(guān)推薦

2017-02-15 09:40:38

JavaScript分析解決

2020-09-09 10:00:41

JavaScript前端瓶頸

2025-10-27 02:11:00

2024-02-02 15:21:08

工具頁面性能

2019-10-31 11:50:19

MySQL數(shù)據(jù)庫Windows

2022-04-29 15:24:53

Redis存儲(chǔ)慢查詢

2022-07-15 08:52:03

Linux優(yōu)化

2024-03-01 12:19:00

接口性能優(yōu)化

2024-11-25 07:00:00

2021-01-24 11:46:26

自動(dòng)化Web 優(yōu)化

2010-03-31 10:25:41

MyEclipse

2019-05-10 11:13:19

分析工具Java

2013-11-26 13:23:14

WAN優(yōu)化Riverbed

2023-04-17 08:04:15

Redis性能內(nèi)存

2019-03-01 11:03:22

Lustre高性能計(jì)算

2024-01-25 16:19:27

2025-08-12 02:10:00

2011-12-12 16:27:02

筆記本方案匯總

2021-07-05 08:58:17

Golang分布式性能

2019-05-23 08:08:33

MySQL數(shù)據(jù)庫DBA
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)