欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS生態(tài)系統(tǒng)加速桶裝文件使用探索

 更新時(shí)間:2024年01月21日 11:00:34   作者:大家的林語(yǔ)冰?人貓神話  
這篇文章主要為大家介紹了JS?生態(tài)系統(tǒng)加速桶裝文件使用實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

JS 桶裝文件

長(zhǎng)話短說(shuō):一大坨項(xiàng)目都塞滿了只是重新 export 其他文件的文件。這就是所謂的“桶裝文件”(barrel files),也是 JS 工具在大型項(xiàng)目中慢如龜速的關(guān)鍵原因之一。

本期《前端翻譯計(jì)劃》共享的是“加速 JS 生態(tài)系統(tǒng)系列博客”,包括但不限于:

  • PostCSS,SVGO 等等
  • 模塊解析
  • 使用 eslint
  • npm 腳本
  • draft-js emoji 插件
  • polyfill 暴走
  • 桶裝文件暴走
  • Tailwind CSS

本期共享的是第 7 篇博客 —— 桶裝文件暴走。

新文件 import

假設(shè)我們正在開(kāi)發(fā)一個(gè)包含一大坨文件的大型項(xiàng)目。我們添加一個(gè)新文件來(lái)處理新功能,并將另一個(gè)目錄中的函數(shù) import 到代碼中。

import { foo } from './some/other-file'

export function myCoolCode() {
  // 假裝這是超智能代碼 :)
  const result = foo()
  return result
}

我們十分雞凍地實(shí)現(xiàn)了功能,我們運(yùn)行代碼,但是發(fā)現(xiàn)這需要很久才能搞定。我們編寫的代碼一目了然,理論上應(yīng)該不會(huì)太費(fèi)時(shí)。為此,我們添加了某些測(cè)量代碼,查看函數(shù)完成其任務(wù)所需的時(shí)間。

import { foo } from './some/other-file'

export function myCoolCode() {
  console.time()
  const result = foo()
  console.timeEnd()
  return result
}

我們重跑代碼,大吃一斤的是,我們插入的測(cè)量結(jié)果表明,我們的函數(shù)速度驚人。我們重復(fù)測(cè)量步驟,但這次在項(xiàng)目的主入口文件中插入 console.time() 語(yǔ)句,然后再重跑代碼。梅開(kāi)二度,記錄的測(cè)量結(jié)果只是反復(fù)證明我們的代碼本身速度驚人。那為什么運(yùn)行代碼卻很費(fèi)時(shí)呢?

沒(méi)時(shí)間解釋了快上車。這就是桶裝文件對(duì)代碼造成的破壞性影響。

收集更多信息

目前為止,我們獲得的關(guān)鍵信息是,代碼的運(yùn)行時(shí)不是 bug 所在。我們測(cè)量了函數(shù),它只是運(yùn)行總時(shí)間的九牛一毛。這意味著,我們可以假設(shè),所有剩余時(shí)間耽誤在運(yùn)行代碼前后。根據(jù)工具的經(jīng)驗(yàn),時(shí)間通?;ㄔ陧?xiàng)目代碼運(yùn)行前。

我有一個(gè)大膽的想法:我們聽(tīng)過(guò)某些 npm 軟件包出于性能考慮,會(huì)預(yù)打包其代碼。也許這是一種新思路?我們決定測(cè)試該理論,并訴諸 esbuild 將代碼打包到一個(gè)簡(jiǎn)單文件中。我們故意禁用任何形式的壓縮,因?yàn)槲覀兿Ma盡可能還原原始源碼。

完事后,我們可以運(yùn)行打包后的文件來(lái)對(duì)照實(shí)驗(yàn),我和我的小伙伴都驚呆了,這次運(yùn)行比貓貓還快。出于好奇,我們測(cè)量了運(yùn)行 esbuild 和一起運(yùn)行打包文件的時(shí)間,并注意到,它們累加起來(lái)仍然比運(yùn)行原始源碼更快。啊?到底是怎么回事?我們明明多了打包步驟,但運(yùn)行結(jié)果卻比未打包的源碼更快?

然后我悟了:打包器的超能力是,拍平和合并模塊圖。得益于 esbuild,曾經(jīng)由數(shù)千個(gè)文件組成的內(nèi)容,被合并為有且僅有一個(gè)簡(jiǎn)單文件。這是一個(gè)有力的證明,模塊圖的大小是源碼運(yùn)行緩慢的 bug 所在。桶裝文件乃速度低下的“萬(wàn)惡之源”。

剖析桶裝文件

所謂“桶裝文件”,指的是僅僅用于 export 其他文件,且本身不包含代碼的文件。在編輯器支持自動(dòng) import 之前,一大坨開(kāi)發(fā)者試圖將它們必須手動(dòng)編寫的 import 語(yǔ)句的數(shù)量保持在最低限度。

// 瞄一眼所有這些 import
import { foo } from '../foo'
import { bar } from '../bar'
import { baz } from '../baz'

這就產(chǎn)生了一種模式,其中每個(gè)文件夾都有自己的 index.js 文件,該文件通常只是從位于同一目錄中的其他文件重新 export 代碼。某種程度上,這分?jǐn)偭耸謩?dòng)輸入工作,因?yàn)橐坏┻@樣的文件就位,所有其他代碼只需要引用一個(gè) import 語(yǔ)句。

// feature/index.js
export * from './foo'
export * from './bar'
export * from './baz'

之前顯示的 import 語(yǔ)句現(xiàn)在可以折疊成一行。

import { foo, bar, baz } from '../feature'

一段時(shí)間后,這種模式在整個(gè)代碼庫(kù)中蔓延,項(xiàng)目中的每個(gè)文件夾都有一個(gè) index.js 文件。十分整潔,對(duì)不?對(duì)對(duì)對(duì),才怪咧。

眾生皆有病

在類似的設(shè)置中,模塊大概率會(huì) import 另一個(gè)桶裝文件,該文件又雙叒叕會(huì)拉入一大坨其他文件,然后 import 另一個(gè)桶裝文件,子子孫孫無(wú)窮盡也。最終,我們通常會(huì)通過(guò) import 語(yǔ)句的“蜘蛛網(wǎng)” import 項(xiàng)目中的每個(gè)文件。項(xiàng)目越大,加載所有這些模塊就越久。

捫心自問(wèn):哪里快了?必須加載 30k 個(gè)文件更快,還是只加載 10 個(gè)更快?

JS 愛(ài)好者的“思想鋼印”在于,模塊只會(huì)按需加載。這大錯(cuò)特錯(cuò),因?yàn)檫@樣做會(huì)破壞依賴全局變量或模塊執(zhí)行順序的代碼。

// a.js
globalThis.foo = 123

// b.js
console.log(globalThis.foo) // 應(yīng)該打印: 123

// index.js
import './a'
import './b'

如果引擎無(wú)法加載首個(gè) ./a 導(dǎo)入,那么代碼會(huì)意外打印 undefined 而不是 123。

桶裝文件的性能瓶頸

當(dāng)我們考慮使用測(cè)試運(yùn)行程序等工具時(shí),情況會(huì)雪上加霜。在人氣爆棚的 Jest 測(cè)試運(yùn)行器中,每個(gè)測(cè)試文件都在其子進(jìn)程中執(zhí)行。實(shí)際上,這意味著,每個(gè)測(cè)試文件都從零開(kāi)始構(gòu)建模塊圖,并且必須支付該成本。如果在項(xiàng)目中構(gòu)建模塊圖需要 6 秒,并且您只有 100 個(gè)測(cè)試文件,那么您總共會(huì)浪費(fèi) 10 分鐘,重復(fù)構(gòu)建模塊圖。在此期間不會(huì)運(yùn)行任何測(cè)試或其他代碼。這正是引擎需要準(zhǔn)備源碼以便運(yùn)行的時(shí)候。

桶裝文件作為“性能殺手”的另一個(gè)法外之地是,任何類型的 import 周期 linting 規(guī)則。通常,linter 按逐個(gè)文件運(yùn)行,這意味著,需要為每個(gè)文件支付構(gòu)建模塊圖的成本。僅此一點(diǎn)就會(huì)導(dǎo)致 linting 時(shí)間爆表,并且在較大的項(xiàng)目中可能需要幾小時(shí),這種情況司空見(jiàn)慣。

為了獲得某些原始數(shù)據(jù),我生成了一個(gè)項(xiàng)目,其中的文件相互 import,以便更好地了解構(gòu)建模塊圖的成本。每個(gè)文件都空空如也,除了 import 語(yǔ)句外,沒(méi)有包含任何代碼。計(jì)時(shí)是在我的“量子計(jì)算機(jī)”上測(cè)量的。

如你所見(jiàn),加載更少的模塊十分值得。讓我們將這些數(shù)字應(yīng)用到一個(gè)包含 100 個(gè)測(cè)試文件的項(xiàng)目,其中使用測(cè)試運(yùn)行程序?yàn)槊總€(gè)測(cè)試文件生成一個(gè)新的子進(jìn)程。我們的測(cè)試運(yùn)行程序可以并行運(yùn)行 4 個(gè)測(cè)試:

500 個(gè)模塊:0.15s * 100 / 4 = 3.75s 開(kāi)銷

1_000 個(gè)模塊:0.31s * 100 / 4 = 7.75s 開(kāi)銷

25_000 個(gè)模塊:16.81s * 100 / 4 = ~7:00m 開(kāi)銷

50_000 個(gè)模塊:48.44s * 100 / 4 = ~20:00m 開(kāi)銷

由于這是一個(gè)綜合設(shè)置,因此這些數(shù)字都是低估的。在實(shí)際項(xiàng)目中,這些數(shù)字可能更糟糕。就工具性能而言,桶裝文件并不友好。

我們?cè)撜k?

代碼中只有少量桶裝文件通常問(wèn)題不大,但當(dāng)每個(gè)文件夾都有就會(huì)出現(xiàn)問(wèn)題。不幸的是,這種災(zāi)難在 JS 行業(yè)屢見(jiàn)不鮮。

因此,如果大家從事的項(xiàng)目廣泛使用桶裝文件,那么可以免費(fèi)優(yōu)化:清空所有桶裝文件,使一大坨任務(wù)速度加快 60-80%。

免責(zé)聲明

本文屬于是語(yǔ)冰的直男翻譯了屬于是,略有刪改,僅供粉絲參考,英文原味版請(qǐng)傳送 Speeding up the JavaScript ecosystem - The barrel file debacle[1]。

以上就是JS 生態(tài)系統(tǒng)加速桶裝文件使用探索的詳細(xì)內(nèi)容,更多關(guān)于JS 桶裝文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論