成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

?TypeScript 源碼啟示:驚人的52000行代碼文件

開發 開源
我們在 review 各大開源 js 倉庫性能實踐的時候注意到:ts 源碼的 checker.ts 這個文件相當暴力,它將 TS 完整類型系統全部邏輯 5.2 萬行全部寫在一個 ts 文件里,而文件大小則達到了驚人的 2.92 MB , 這相當為什么?

作者 | ecznlai

重型 JS 項目的性能問題一向很難,我們在 review 各大開源 js 倉庫性能實踐的時候注意到:ts 源碼的 checker.ts 這個文件相當暴力,它將 TS 完整類型系統全部邏輯 5.2 萬行全部寫在一個 ts 文件里,而文件大小則達到了驚人的 2.92 MB —— 這相當有趣,為什么?

大名鼎鼎的 checker.ts 這個文件我很久以前就知道了, 在 Github 上直接打不開:Github - microsfot/Github: ./src/compiler/checker.ts

好,VSCode,啟動:

五萬行 all-in-one 的 checker.ts

這個文件很暴力,類型系統全部邏輯 5 萬行 all-in-one file ,是 ts 源碼維護者不會寫代碼嗎?顯然并不是,我翻了一些資料和讀了下其中的實現,稍微震撼了一下,將相關思考細節記錄在本文。

低配版 named parameters

眾所周知,js 各種規范都推薦你用一個對象來傳遞多個參數,然后在函數里解構 —— 多數時候這沒什么,但是在 ts compiler 里,任何浪費都會被極限放大,因此他們用了這種低配版用注釋的方式來表示 named parameters (這行還是 anders 老爺子寫的,C# 之父 編程領域的傳奇!C#、TypeScript之父!全世界最頂尖的程序員之一。-騰訊云開發者社區-騰訊云 )

何為 named parameter 呢?其實就是帶名字標簽的函數,調用的時候可以指定標簽來傳參數,這個在其他語言里是基操,比如 moonbit or swift 里的標簽函數:

fn add(~left: Int, ~right: Int) -> Int {
  return left + right;
}

add(left: 1, right: 44); // ?? 
add(right: 44, left: 1); // ?? 
add(1, 2);               // ??此時會自動匹配到 left 和 right

為什么 ts 需要 named parameter 特性: 在 ts 這種高頻調用場景里通過解構 options 對象的方式傳參會導致大量無謂的內存開銷 —— 這通常會導致 type checking 過程中的內存峰值而造成頻繁 gc & mem_copy 更重要的是字面量 key 的順序還會影響 v8 的 inline caches 優化,寫的不好可能會對函數調用 feedback 造成嚴重負面反饋進而影響 TurboFan 的進一步優化最后造成非常大的性能損失 ...

當 V8 函數調用的 feedback slot 從 SMI 變成 Any 時,TurboFan codegen 的匯編將會慢三倍,關于這個問題的細節,我們在這里有深度討論&實踐。

能用 number 盡量 number

比如 switch、比如 const enum、比如各種 enum bitmap flags 等等設計,原因是 object 和 string 的開銷太大了,而小一點的整數在 v8 里甚至是無開銷的(如果 SMI tagged pointer 指針自身數值不算開銷的話)。

無限制使用 const enum

const enum 有個特性可以直接 inline 枚舉值到函數里變成立即數,能享受極致優化:

但目前社區對于 const enum 的主流意見是 不推薦使用,而且 ts 的部分維護者也認為這個是 mistake:

但是這說法其實相當尷尬:是的雖然這是 mistake 我們不推薦使用,但我們 ts 源碼里全都是 const enum 到處飛 ... (800+ 個 const enum,沒這個特性估計 tsc 要慢不少)

ESM/CJS 的性能問題:尤其是 export 導出特別多的時候

當 export 導出太多成員的情況下,V8 內部處理這類對象會將其變成 Slow Properties 字典模式,在多數時候這沒啥,但如果遇到某高頻模塊內的常量被引用大幾百萬次的情況下,此時 export.xxxxx 的點讀查詢開銷就不能忽視了,尤其是當 export 上有幾百個導出的時候,此時點讀開銷不可忽視,比如:

const constant = require(`./constant`);

module.export = function getXXConfig() {
  return constant.xxx + constant.bbb;
}
// 由于 constant 上有幾百個常量,
// 即使是 constant.xxx 這樣簡單的語句
// 在百萬次調用的時候,其耗時將不可忽略 ( 幾百 ms 以上 )

而 checker.ts 則是將所有東西 all in one,就沒這問題了,全都在函數作用域內,查詢時間是 O(1)。

ESM 沒有 private 導出

有種 export 是只想在項目內無限制使用,但是又不期望導出能被外部的 npm 看到 —— 也就是 esm 沒有提供 private export 這種特性:

import D from '@tencent/xxx/a/b/c/d';
// ?? 我不期望別人能這樣 import 我內部的東西

而 ts 又恰恰要這種特性,那么它們怎么實現的呢?通過 /** @internal */ 注解,比如:

標記為 @internal 的東西在生成 d.ts 的時候會被抹去,變相實現外部無法 import 而 ts 倉庫內隨便 import 。

ts 甚至大量使用 var,而不是用 let 和 const

又比如,有部分函數為了性能全用 var,愣是沒用 const / let 這些,你看 ts 怎么寫的:

具體見: github.com/microsoft...

大意是 ts 的場景下,v8 這類 js runtime 的 TDZ 檢查甚至會相當影響運行性能。。。畢竟五萬行呢。。。(production build 會比 dev build 要快不少的原因之一)

往 String.prototype.xxx 上注入東西

這類操作在普通 js/ts 項目里是一定會被鄙視的,但一個靜態類型語言怎么沒辦法自己拓展基礎類型來使用呢?(這在 swift / go 之類的語言里基于 string / int 來搞出一個新的類型出來是基操。)

無類編程,推崇組合編程

checker.ts 幾萬行核心邏輯幾乎沒有 class 和繼承,完全通過函數組合的方式來架構代碼,整體看著像是有 rust impl 關鍵字的 ts 那樣:

代碼里大部分函數都是上面這種風格,第一個參數是「核心接口」其他參數則是對應的參數,當然,組合優于繼承也算是近年來業界達成的共識了。

當然比起架構,我更愿意相信 ts 是考慮到 class 繼承可能存在潛在的性能問題導致的:

比如 V8 引擎下的 A extends B 場景,B 上面有個方法 fn,當 A.fn(); B.fn(); 都調用了之后,如果 A 和 B 的 shapes 不一樣,此時 fn 調用 feedback slot 會從 monomorphic 的變成 polymorphic 的,當繼承三個以上的時候就會變成 megamorphic 了,這會影響引擎 ICs 的優化效果,導致性能下降。

怎么沒有用「表驅動」這種所謂的常用「前端設計模式」?

圖片

源碼里很多這種根據 ast node kind 去走不同邏輯,然后這些邏輯都寫成 if else if else 或者 switch 語句 —— 為何不使用一個 Record<Kind, Fn> 的方式去表驅動呢?

原因很簡單:表驅動無法被 v8 這類 runtime 靜態分析優化,而且表驅動這類寫法會慢個幾十倍對于基礎設施來說這是不可接受的。(無貶義,js 的表驅動寫法看場景,高頻調用還是別了吧,寫 event selector 之類的倒是一類比較合適的場景)。

從語言特性的層面來說,ts 真的缺一個滿血版模式匹配 + enum adt 了,但目前 ts 原則上是不會再合入新的 runtime 特性了 —— 這就很難受了,又不能表驅動,又不能模式匹配,最后代碼很 C style 了,而且要寫非常多的 x is X 謂語 。

基本沒有 try-catch

與 go 有類似的想法,checker.ts 里通過返回值 + 往 context.xxx 上寫東西的方式來指示異常,一方面是為了性能,另外一方面我甚至可以合理懷疑為是沒有 checked exception 導致只能這樣才能 type checked ... (當然 anders 老爺子應該是 uncheck 黨,參考 C# 的設計)

文件多才是大問題 —— 可惜了半成品的 ts namespace

如果有接觸過大型 js/ts 項目的同學肯定知道,文件一多就不知道東西在哪了,找個 import 你甚至要垮十幾個文件 。

—— 從這也可看到,東西為什么要 import 才讓用呢?能否有 moonbit、rust 那樣好用的模塊系統呢??? 但這依然涉及 runtime 改造,現階段 ts 就別想了,當然 tc39 也不會再考慮這類特性就是了,等一個 TypeScript Pro Max 吧。

關于 namespace:有接觸過 go Rust C++ 的同學應該都有了解了,是用來管理包及語言符號的特性,是業內比較通用的解決方案。

在 ESM 落地之前,ts 有嘗試去做滿血版的 namespace 特性,但是由于重新確定了不做運行時的想法,因此這個特性在成熟之前就放棄迭代而全面轉向 ESM 了,至今 ts 源碼里還大量使用 namespace 或者用 ESM 模擬出 namesapce 特性:

最后來個暴論:JS 已經嚴重影響 TS 的演進了

不得不說,ts 如果繼續死磕 js/tc39 而放棄做 runtime feature,恐怕現在已經是最終形態了 ... 以后不會有更進一步的演進了,因為目前 ts 類型系統已經相當完善了,甚至部分能力其他語言都沒有,比如 Union Types 以及領先各大友商的控制流分析技術(然而,2024 了 ts 還沒有滿血版 ADT + 模式匹配,因為這屬于 runtime 特性,不是簡單擦掉類型就能搞定的)。

當然,近期 tc39 雖然也提了不少新東西但是沒有靜態類型系統就顯得這些特性相當雞肋以至于它們看起來就像是 ts39 一樣,比如備受關注的 Record & Tuple 已經到 Stage 2 了,但懂得都懂這特性一看就知道明顯就是給 ts 設計的,給 js 用這個特性跟到處傳 void* 一樣沒什么區別,因為這東西是運行時強類型的,也就是訪問 one_record.x 如果真的沒有定義 x 那么會直接拋出 error 的而不是返回 undefined。

此外這東西太猛了,幾乎就是一個 C 語言版的 匿名 struct 定義對象+內存結構的方案了,我估計各大瀏覽器估計都不太想搞這個 —— 這個要大改引擎的 js 對象模型了,如果真能實裝我很期待它的性能表現。

總之,就目前 ts 源碼倉庫來看,js 自身的語言特性已經極其限制 ts 對其自身的實現了,但是 ts 又承諾不再做新的 runtime 特性,只做類型系統,這就相當擰巴了,尤其是體現在 ts 源碼里,這要是放在公司,晉級 CR 估計要涼透了(悲)

EOF

checker.ts 已經搞出幾萬行文件以及大量 if-else 超高復雜度的控制流了,還自己手寫 named para 注釋、甚至不用 const / let / class 。而且從代碼里處處可見 ts 相當鄙視 esm 和 cjs 這些 module 方案,覺得性能不行,然后搞出來一個半成品的 namespace 模塊方案。

總之由于 js 特性太少了,導致源碼實現相當擰巴,雖然如此但 ts 整體的 compiler pipeline 架構設計卻相當漂亮和簡潔,尤其是 transfomers 和 anders 老爺子主推的 LSP 所帶來的 IDE 革命,有機會我單開一篇談談這個。

責任編輯:趙寧寧 來源: 騰訊技術工程
相關推薦

2015-02-06 09:37:13

程序員

2018-10-07 15:10:49

2021-02-18 18:47:02

比特幣加密貨幣區塊鏈

2022-08-04 09:01:45

TypeScriptMicrosoft

2021-01-06 14:42:09

前端Typescript代碼

2009-05-20 13:28:28

蘋果Iphone移動OS

2024-05-07 16:38:25

2020-06-10 07:40:36

CPU內核態多線程

2022-07-14 16:27:11

邊緣計算智慧城市應用

2012-12-24 09:45:21

2020-05-06 22:01:52

Excel代碼Python

2021-02-20 23:33:34

TypeScript代碼開發

2025-01-14 00:01:01

2022-11-03 18:28:05

C語言Vely

2025-02-26 10:11:01

2020-12-24 07:02:07

CSS框架

2017-04-10 09:59:08

python代碼愛心線

2014-11-11 14:51:56

2013-03-12 09:22:32

2017-04-11 09:00:24

機器學習發展歷程啟示
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩成人在线视频 | 亚洲一区二区成人 | 亚洲一区二区在线视频 | 日日爱视频 | 久久久久久亚洲精品不卡 | 久久人人网 | 国产精品日日做人人爱 | 欧美a级成人淫片免费看 | 欧美国产日韩在线观看成人 | 日日干夜夜草 | 中文字幕亚洲精品在线观看 | 日韩高清成人 | 2021天天干夜夜爽 | 在线国产小视频 | 亚洲区中文字幕 | 精品欧美一区二区中文字幕视频 | 亚洲一区二区三区桃乃木香奈 | 91亚洲精品久久久电影 | 在线观看中文字幕 | 日韩欧美国产综合 | 欧美 日韩 中文 | 久久精品综合 | 色网在线观看 | 国内精品久久久久久 | 国产电影一区二区 | 亚洲一区在线日韩在线深爱 | 欧美久久一区二区 | 日韩一级 | av电影手机版 | 女人牲交视频一级毛片 | 国产精品久久国产精品 | 欧洲视频一区二区 | 国产偷录叫床高潮录音 | 日本精品网站 | 国产精品a一区二区三区网址 | 免费观看一级毛片视频 | 亚洲aⅴ精品 | 日韩欧美网| 一区二区三区回区在观看免费视频 | 欧美一区二区三区视频在线观看 | www.99久久.com |