摘要:的目標(biāo)是對高級程序中間表示的適當(dāng)?shù)图壋橄螅创a旨在由編譯器生成而不是由人來寫。表示把源代碼變成解釋器可以運(yùn)行的代碼所花的時間表示基線編譯器和優(yōu)化編
WebAssembly 那些事兒 什么是 WebAssembly?
WebAssembly 是除 JavaScript 以外,另一種可以在網(wǎng)頁中運(yùn)行的編程語言,并且相比之下在某些功能和性能問題上更具優(yōu)勢,過去我們想在瀏覽器中運(yùn)行代碼來對網(wǎng)頁中各種元素進(jìn)行控制,只有 JavaScript 這一種選擇,而如今我們可以將其它語言(C/C++ etc.)編譯成 wasm 格式的代碼在瀏覽器中運(yùn)行。
WebAssembly 的目標(biāo)是對高級程序中間表示的適當(dāng)?shù)图壋橄螅?wasm 代碼旨在由編譯器生成而不是由人來寫。
每一種目標(biāo)匯編語言(x86、ARM etc.)都依賴于特定的機(jī)器結(jié)構(gòu),當(dāng)我們想要把代碼放到用戶的機(jī)器上執(zhí)行的時候,并不知道目標(biāo)機(jī)器結(jié)構(gòu)是什么樣的,而 WebAssembly 與其他的匯編語言不一樣,它不依賴于具體的物理機(jī)器,可以抽象地理解成它是 概念機(jī)器的機(jī)器語言,而不是實際的物理機(jī)器的機(jī)器語言,正因為如此 WebAssembly 指令有時也被稱為虛擬指令,它比 JavaScript 代碼更直接地映射到機(jī)器碼,同時它也代表了“如何能在通用的硬件上更有效地執(zhí)行代碼”的一種理念。
目前對于 WebAssembly 支持情況最好的編譯器工具鏈?zhǔn)?LLVM,還有一個易用的工具叫做 Emscripten,它通過自己的后端先把代碼轉(zhuǎn)換成自己的中間代碼(asm.js),然后再轉(zhuǎn)化成 WebAssembly,實際上它是基于 LLVM 的一系列編譯工具的集合。
Tip:很多 WebAssembly 開發(fā)者用 C 語言或者 Rust 開發(fā),再編譯成 WebAssembly,其實還有其他的方式來開發(fā) WebAssembly 模塊:使用 TypeScript 開發(fā) WebAssembly 模塊,或者直接書寫 WebAssembly 文本 etc.。
WebAssembly 代碼存儲在 .wasm 文件內(nèi),這類文件是要瀏覽器直接執(zhí)行的,因為 .wasm 文件內(nèi)是二進(jìn)制文件難以閱讀,為方便開發(fā)者查看官方給出對 .wasm 文件的閱讀方法:
把 .wasm 文件通過工具轉(zhuǎn)為 .wast 的文本格式,開發(fā)者可以在一定程度上理解這個 .wast 文件(通過 S- 表達(dá)式寫成,類似于 lisp 語言的代碼書寫風(fēng)格)。
Tip:.wast 文件和 .wasm 文件之間的相互轉(zhuǎn)化可以通過工具 wabt 實現(xiàn)。為什么 WebAssembly 更快? 一些關(guān)于性能的歷史
- JavaScript 于 1995 年問世,它的設(shè)計初衷并不是為了執(zhí)行起來快,在前 10 個年頭它的執(zhí)行速度也確實不快。
- 緊接著,瀏覽器市場競爭開始激烈起來。
- 廣為流傳的“性能大戰(zhàn)”在 2008 年打響,許多瀏覽器引入 JIT 編譯器,JavaScript 代碼的運(yùn)行速度漸漸變快(10倍!),這使得 JavaScript 的性能達(dá)到一個轉(zhuǎn)折點。
知識遷移:Javascript JIT 工作原理在代碼的世界中,通常有兩種方式來翻譯機(jī)器語言:解釋器和編譯器。
如果是通過解釋器,翻譯是一行行地邊解釋邊執(zhí)行
編譯器是把源代碼整個編譯成目標(biāo)代碼,執(zhí)行時不再需要編譯器,直接在支持目標(biāo)代碼的平臺上運(yùn)行
解釋器啟動和執(zhí)行的更快,我們不需要等待整個編譯過程完成就可以運(yùn)行代碼,從第一行開始翻譯就可以依次繼續(xù)執(zhí)行。正是因為這個原因,解釋器看起來更加適合 JavaScript,對于一個 Web 開發(fā)人員來講,能夠快速執(zhí)行代碼并看到結(jié)果是非常重要的。可是當(dāng)我們運(yùn)行同樣的代碼一次以上的時候,解釋器的弊處就顯現(xiàn)出來:比如執(zhí)行一個循環(huán),那解釋器就不得不一次又一次的進(jìn)行翻譯,這是一種效率低下的表現(xiàn)。
編譯器的問題則恰好相反:它需要花一些時間對整個源代碼進(jìn)行編譯,然后生成目標(biāo)文件才能在機(jī)器上執(zhí)行。對于有循環(huán)的代碼執(zhí)行的很快,因為它不需要重復(fù)的去翻譯每一次循環(huán)。
另外一個不同是,編譯器可以用更多的時間對代碼進(jìn)行優(yōu)化,以使的代碼執(zhí)行的更快;而解釋器是在 runtime 時進(jìn)行這一步驟的,這就決定它不可能在翻譯的時候用很多時間進(jìn)行優(yōu)化。
為了解決解釋器的低效問題,后來的瀏覽器把編譯器也引入進(jìn)來,形成混合模式。不同的瀏覽器實現(xiàn)這一功能的方式不同,不過其基本思想是一致的:在 JavaScript 引擎中增加一個監(jiān)視器(也叫分析器),監(jiān)視器監(jiān)控著代碼的運(yùn)行情況,記錄代碼一共運(yùn)行多少次、如何運(yùn)行等信息。
起初,監(jiān)視器監(jiān)視著所有通過解釋器的代碼,如果同一行代碼運(yùn)行多次,這個代碼段就被標(biāo)記成 “warm”,如果運(yùn)行很多次則被標(biāo)記成 “hot”。
如果一段代碼變成 “warm”,那么 JIT 就把它送到編譯器去編譯,并且把編譯結(jié)果存儲起來。
代碼段的每一行都會被編譯成一個“樁”(stub),同時給這個樁分配一個以“行號 + 變量類型”的索引,如果監(jiān)視器監(jiān)視到執(zhí)行同樣的代碼和同樣的變量類型,那么就直接把這個已編譯的版本 push 出來給瀏覽器。通過這樣的做法可以加快執(zhí)行速度,但是正如前我所說的,編譯器還可以找到更有效地執(zhí)行代碼的方法(優(yōu)化)。
基線編譯器可以做一部分這樣的優(yōu)化,不過基線編譯器優(yōu)化的時間不能太久,因為會使得程序的執(zhí)行在這里 hold 住,不過如果代碼確實非常 “hot”(也就是說幾乎所有的執(zhí)行時間都耗費在這里),那么花點時間做優(yōu)化也是值得的。
如果一個代碼段變得 “very hot”,監(jiān)視器會把它發(fā)送到優(yōu)化編譯器中,生成一個更快速和高效的代碼版本出來,并且存儲之。為了生成一個更快速的代碼版本,優(yōu)化編譯器必須做一些假設(shè):例如它會假設(shè)由同一個構(gòu)造函數(shù)生成的實例都有相同的形狀,就是說所有的實例都有相同的屬性名,并且都以同樣的順序初始化,那么就可以針對這一模式進(jìn)行優(yōu)化。
整個優(yōu)化器起作用的鏈條是這樣的,監(jiān)視器從他所監(jiān)視代碼的執(zhí)行情況做出自己的判斷,接下來把它所整理的信息傳遞給優(yōu)化器進(jìn)行優(yōu)化,如果某個循環(huán)中先前每次迭代的對象都有相同的形狀,那么就可以認(rèn)為它以后迭代的對象的形狀都是相同的,可是對于 JavaScript 從來就沒有保證這么一說,前 99 個對象保持著形狀,可能第 100 個就減少某個屬性。
正是由于這樣的情況,編譯代碼需要在運(yùn)行之前檢查其假設(shè)是不是合理的,如果合理那么優(yōu)化的編譯代碼會運(yùn)行,如果不合理那么 JIT 會認(rèn)為這是一個錯誤的假設(shè),并且把優(yōu)化代碼丟掉,這時執(zhí)行過程將會回到解釋器或者基線編譯器,這一過程叫做去優(yōu)化。
通常優(yōu)化編譯器會使得代碼變得更快,但是一些情況也會引起一些意想不到的性能問題。如果代碼一直陷入優(yōu)化去優(yōu)化的怪圈,那么程序執(zhí)行將會變慢,還不如基線編譯器快。大多數(shù)的瀏覽器限制當(dāng)優(yōu)化去優(yōu)化循環(huán)發(fā)生的時候會嘗試跳出這種循環(huán),比如如果 JIT 反復(fù)做 10 次以上的優(yōu)化并且又丟棄的操作,那么就不繼續(xù)嘗試去優(yōu)化這段代碼。
JavaScript 所使用的動態(tài)類型體系在運(yùn)行時需要進(jìn)行額外的解釋工作,例如下面代碼:
function arraySum(arr) { var sum = 0; for (var i = 0; i < arr.length; i++) { sum += arr[i]; } }
+= 循環(huán)中這一步看起來很簡單,只需要進(jìn)行一步計算,但是恰恰因為是用動態(tài)類型,所需要的步驟要比我們所想象的更復(fù)雜一些:我們假設(shè) arr 是一個有 100 個整數(shù)的數(shù)組,當(dāng)代碼被標(biāo)記為 “warm” 時,基線編譯器就為函數(shù)中的每一個操作生成一個樁,sum += arr[i]會有一個相應(yīng)的樁,并且把里面的 += 操作當(dāng)成整數(shù)加法,但是 sum 和 arr[i] 兩個數(shù)并不保證都是整數(shù),因為在 JavaScript 中類型都是動態(tài)類型,在接下來的循環(huán)當(dāng)中 arr[i] 很有可能變成了string 類型,整數(shù)加法和字符串連接是完全不同的兩個操作,會被編譯成不同的機(jī)器碼。
JIT 處理這個問題的方法是編譯多基線樁:如果一個代碼段是單一形態(tài)的(即總是以同一類型被調(diào)用),則只生成一個樁:如果是多形態(tài)的(即調(diào)用的過程中,類型不斷變化),則會為操作所調(diào)用的每一個類型組合生成一個樁。這就是說 JIT 在選擇一個樁之前會進(jìn)行多分枝選擇(類似于決策樹),問自己很多問題才會確定最終選擇哪個。
正是因為在基線編譯器中每行代碼都有自己的樁,所以 JIT 在每行代碼被執(zhí)行的時候都會檢查數(shù)據(jù)類型,在循環(huán)的每次迭代 JIT 也都會重復(fù)一次分枝選擇。
如果代碼在執(zhí)行的過程中 JIT 不是每次都重復(fù)檢查的話,那么執(zhí)行的還會更快一些,而這就是優(yōu)化編譯器所需要做的工作之一。在優(yōu)化編譯器中,整個函數(shù)被統(tǒng)一編譯,這樣的話就可以在循環(huán)開始執(zhí)行之前進(jìn)行類型檢查。
一些瀏覽器的 JIT 優(yōu)化更加復(fù)雜:在 Firefox 中給一些數(shù)組設(shè)定特定的類型,比如數(shù)組里面只包含整型,如果 arr 是這種數(shù)組類型,那么 JIT 就不需要檢查 arr[i] 是不是整型,這也意味著 JIT 可以在進(jìn)入循環(huán)之前進(jìn)行所有的類型檢查。
- 隨著性能的提升 JavaScript 可以應(yīng)用到更多領(lǐng)域(Node.js etc.)
- 通過 WebAssembly 我們很有可能正處于第二個拐點!
當(dāng)前的 JavaScript 性能如何?下圖片介紹 JS 引擎性能使用的大概分布情況,各個部分所花的時間取決于頁面所用的 JavaScript 代碼,其比例并不代表真實情況下的確切比例情況,并且這些任務(wù)并不是離散執(zhí)行或者按固定順序依次執(zhí)行的,而是交叉執(zhí)行:比如某些代碼在進(jìn)行解析時,其他一些代碼正在運(yùn)行而另一些正在編譯。
Parsing:表示把源代碼變成解釋器可以運(yùn)行的代碼所花的時間;
Compiling + optimizing:表示基線編譯器和優(yōu)化編譯器所花的時間(某些優(yōu)化編譯器的工作并不在主線程運(yùn)行)
Re-optimizing:當(dāng) JIT 發(fā)現(xiàn)優(yōu)化假設(shè)錯誤,丟棄優(yōu)化代碼所花的時間(包括重優(yōu)化的時間、拋棄并返回到基線編譯器的時間)
Execution:執(zhí)行代碼的時間
Garbage collection:垃圾回收、清理內(nèi)存的時間
早期的 JavaScript 執(zhí)行類似于下圖,各個過程順序進(jìn)行:
各個瀏覽器處理下圖中不同的過程有著細(xì)微的差別,我們使用 SpiderMonkey 作為模型來講解不同的階段:
文件獲取這一步并沒有顯示在圖表中,但是看似簡單的從服務(wù)器獲取文件得這個步驟,卻會花費很長時間,WebAssembly 比 JavaScript 的壓縮率更高,即在服務(wù)器和客戶端之間傳輸文件更快,尤其在網(wǎng)絡(luò)不好的情況下。
解析當(dāng)文件到達(dá)瀏覽器時 JavaScript 源代碼就被解析成抽象語法樹,瀏覽器采用懶加載的方式進(jìn)行,只解析真正需要的部分,而對于瀏覽器暫時不需要的函數(shù)只保留它的樁。解析過后 AST(抽象語法樹)就變成了中間代碼(字節(jié)碼:一種中間代碼,通過虛擬機(jī)轉(zhuǎn)換為機(jī)器語言)提供給 JS 引擎編譯,而 WebAssembly 則不需要這種轉(zhuǎn)換,因為它本身就是中間代碼,要做的只是解碼并且檢查確認(rèn)代碼沒有錯誤即可。
抽象語法樹(Abstract Syntax Tree)也稱為 AST 語法樹,指的是源代碼語法所對應(yīng)的樹狀結(jié)構(gòu)。
程序代碼本身可以被映射成為一棵語法樹,而通過操縱語法樹我們能夠精準(zhǔn)的獲得程序代碼中的某個節(jié)點。Espsrima 提供一個在線解析的工具,我們可以借助于這個工具將 JavaScript 代碼解析為一個 JSON 文件表示的樹狀結(jié)構(gòu),舉例如下所示:
// Life, Universe, and Everything var answer = 6 * 7;
{ "type": "Program", "body": [ { "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "answer" }, "init": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Literal", "value": 6, "raw": "6" }, "right": { "type": "Literal", "value": 7, "raw": "7" } } } ], "kind": "var" } ], "sourceType": "script" }
抽象語法樹的作用非常的多,比如編譯器、IDE、壓縮優(yōu)化代碼 etc.,在 JavaScript 中雖然我們并不會常常與 AST 直接打交道,但卻也會經(jīng)常涉及到它的使用:例如使用 UglifyJS 來壓縮代碼時,這背后的原理就是在對 JavaScript 的抽象語法樹進(jìn)行操作。
編譯和優(yōu)化JavaScript 是在代碼的執(zhí)行階段編譯的,因為它是弱類型語言,當(dāng)變量類型發(fā)生變化時,同樣的代碼會被編譯成不同版本,不同瀏覽器處理 WebAssembly 的編譯過程也不同,有些瀏覽器只對 WebAssembly 做基線編譯,而另一些瀏覽器用 JIT 來編譯,不論哪種方式,WebAssembly 都更貼近機(jī)器碼所以它更快:
在編譯優(yōu)化代碼之前不需要提前運(yùn)行代碼以知道變量都是什么類型
編譯器不需要對同樣的代碼做不同版本的編譯
很多優(yōu)化在 LLVM 階段就已經(jīng)完成
重優(yōu)化有些情況下 JIT 會反復(fù)地進(jìn)行拋棄優(yōu)化代重優(yōu)化過程,當(dāng) JIT 在優(yōu)化假設(shè)階段做的假設(shè)在執(zhí)行階段發(fā)現(xiàn)是不正確的時候,就會發(fā)生這種情況:比如當(dāng)循環(huán)中發(fā)現(xiàn)本次循環(huán)所使用的變量類型和上次循環(huán)的類型不一樣,或者原型鏈中插入了新的函數(shù),都會使 JIT 拋棄已優(yōu)化的代碼。
需要花時間丟掉已優(yōu)化的代碼并且回到基線版本
如果函數(shù)依舊頻繁被調(diào)用,JIT 可能會再次把它發(fā)送到優(yōu)化編譯器又做一次優(yōu)化編譯
而在 WebAssembly 中類型都是確定的,所以 JIT 不需要根據(jù)變量的類型做優(yōu)化假設(shè),也就是說 WebAssembly 沒有重優(yōu)化階段。
執(zhí)行開發(fā)人員自己也可以寫出執(zhí)行效率很高的 JavaScript 代碼,這需要了解 JIT 的優(yōu)化機(jī)制,例如要知道什么樣的代碼編譯器會對其進(jìn)行特殊處理,然而大多數(shù)的開發(fā)者是不知道 JIT 內(nèi)部的實現(xiàn)機(jī)制的,即使知道 JIT 的內(nèi)部機(jī)制也很難寫出符合 JIT 標(biāo)準(zhǔn)的代碼,因為人們通常為了代碼可讀性更好而使用的編碼模式恰恰不合適編譯器對代碼的優(yōu)化;加之 JIT 會針對不同的瀏覽器做不同的優(yōu)化,所以對于一個瀏覽器優(yōu)化的比較好,很可能在另外一個瀏覽器上執(zhí)行效率就比較差。
正是因為這樣執(zhí)行 WebAssembly 通常會比較快,很多 JIT 為 JavaScript 所做的優(yōu)化在 WebAssembly 并不需要;另外 WebAssembly 就是為編譯器而設(shè)計的,開發(fā)人員不直接對其進(jìn)行編程,這樣就使得 WebAssembly 專注于提供更加理想的指令(執(zhí)行效率更高的指令)給機(jī)器即可。
垃圾回收JavaScript 中開發(fā)者不需要手動清理內(nèi)存中不用的變量,JS 引擎會自動地做這件事情即垃圾回收的過程。可是當(dāng)我們想要實現(xiàn)性能可控,垃圾回收可能就是一個大問題:垃圾回收器會自動開始,這是不受控制的,所以很有可能它會在一個不合適的時機(jī)啟動,目前的大多數(shù)瀏覽器已經(jīng)能給垃圾回收安排一個合理的啟動時間,不過這還是會增加代碼執(zhí)行的開銷。
目前為止 WebAssembly 不支持垃圾回收,內(nèi)存操作都是手動控制的,這對于開發(fā)者來講確實會增加開發(fā)成本,不過也使得代碼的執(zhí)行效率更高。
WebAssembly 的現(xiàn)在與未來 JavaScript 和 WebAssembly 之間調(diào)用的中間函數(shù)目前在 Javascript 中調(diào)用 WebAssembly 的速度比本應(yīng)達(dá)到的速度要慢,這是因為中間需要做一次“蹦床運(yùn)動”:JIT 沒有辦法直接處理 WebAssembly,所以 JIT 要先把 WebAssembly 函數(shù)發(fā)送到懂它的地方,這一過程是引擎中比較慢的地方。
按理來講,如果 JIT 知道如何直接處理 WebAssembly 函數(shù),那么速度會有百倍的提升,如果我們傳遞的是單一任務(wù)給 WebAssembly 模塊,那么不用擔(dān)心這個開銷,因為只有一次轉(zhuǎn)換,也會比較快,但是如果是頻繁地從 WebAssembly 和 JavaScript 之間切換,那么這個開銷就必須要考慮了。
快速加載JIT 必須要在快速加載和快速執(zhí)行之間做權(quán)衡,如果在編譯和優(yōu)化階段花了大量的時間,那么執(zhí)行的必然會很快,但是啟動會比較慢。目前有大量的工作正在研究,如何使預(yù)編譯時間和程序真正執(zhí)行時間兩者平衡。WebAssembly 不需要對變量類型做優(yōu)化假設(shè),所以引擎也不關(guān)心在運(yùn)行時的變量類型,這就給效率的提升提供了更多的可能性,比如可以使編譯和執(zhí)行這兩個過程并行。加之最新增加的 JavaScript API 允許 WebAssembly 的流編譯,這就使得在字節(jié)流還在下載的時候就啟動編譯。
FireFox 目前正在開發(fā)兩個編譯器系統(tǒng):一個編譯器先啟動,對代碼進(jìn)行部分優(yōu)化,在代碼已經(jīng)開始運(yùn)行時,第二個編譯器會在后臺對代碼進(jìn)行全優(yōu)化,當(dāng)全優(yōu)化過程完畢,就會將代碼替換成全優(yōu)化版本繼續(xù)執(zhí)行。
添加后續(xù)特性到 WebAssembly 標(biāo)準(zhǔn)的過程 直接操作 DOM目前 WebAssembly 沒有任何方法可以與 DOM 直接交互,就是說我們還不能通過比如 element.innerHTML 的方法來更新節(jié)點。想要操作 DOM 必須要通過 JS,那么就要在 WebAssembly 中調(diào)用 JavaScript 函數(shù),不管怎么樣都要通過 JS 來實現(xiàn),這比直接訪問 DOM 要慢得多,所以這是未來一定要解決的一個問題。
共享內(nèi)存的并發(fā)性提升代碼執(zhí)行速度的一個方法是使代碼并行運(yùn)行,不過有時也會適得其反,因為不同的線程在同步的時候可能會花費更多的時間。這時如果能夠使不同的線程共享內(nèi)存,那就能降低這種開銷,實現(xiàn)這一功能 WebAssembly 將會使用 JavaScript 中的 SharedArrayBuffer,而這一功能的實現(xiàn)將會提高程序執(zhí)行的效率。
SIMD(單指令,多數(shù)據(jù))SIMD(Single Instruction, Multiple Data)在處理存放大量數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)有其獨特的優(yōu)勢,比如存放很多不同數(shù)據(jù)的 vector(容器),就可以用同一個指令同時對容器的不同部分做處理,這種方法會大幅提高復(fù)雜計算的效率比如游戲或者 VR 應(yīng)用。
異常處理許多語言都仿照 C++ 式的異常處理,但是 WebAssembly 并沒有包含異常處理,如果我們用 Emscripten 編譯代碼,就知道它會模擬異常處理,但是這一過程非常之慢,慢到想用 “DISABLEEXCEPTIONCATCHING” 標(biāo)記把異常處理關(guān)掉。如果異常處理加入到 WebAssembly 中那就不必再采用模擬的方式,而異常處理對于開發(fā)者來講又特別重要,所以這也是未來的一大功能點。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/110133.html
摘要:對于很多沒有中間語言的字節(jié)碼的編程語言來說,根本不存在解釋執(zhí)行與編譯執(zhí)行的選項,比如傳統(tǒng)只能編譯執(zhí)行,直接將代碼編譯成為可執(zhí)行的二進(jìn)制機(jī)器碼,我們電腦上文件就是編譯的成果。 Daniel Larimer 在最近的博客中透露,EOS 新增了官方的 WebAssembly 解釋器,用來解釋執(zhí)行 WebAssembly 智能合約,加上之前的編譯執(zhí)行,EOS 智能合約有了兩種執(zhí)行方式。 對于很...
摘要:抽象語法樹大致流程生成然后通過類型斷言進(jìn)行相應(yīng)的轉(zhuǎn)換反編譯工具全集小程序推薦逆向反編譯四大工具利器年支持的反編譯工具匯總原文 像軟件加密與解密一樣,javascript的混淆與解混淆同屬于同一個范疇。道高一尺,魔高一丈。沒有永恒的黑,也沒有永恒的白。一切都是資本市場驅(qū)動行為,現(xiàn)在都流行你能為人解決什么問題,這個概念。那么市場究竟能容納多少個能解決這種問題的利益者。JS沒有秘密。 其實本...
摘要:前端日報精選帶來哪些新特性一之中的無狀態(tài)和有狀態(tài)組件譯使用柵格和打造布局與聯(lián)合發(fā)布中文譯學(xué)習(xí)個常見錯誤阻礙你進(jìn)步掘金里的新玩意知乎專欄介紹掘金壓測方案之簡介那些事兒新技術(shù)全拆解剖析個人文章和項目開發(fā)商城前端課堂 2017-09-15 前端日報 精選 Node.js 8.5 帶來哪些新特性CSS Masonry Layouts【一】之 multi-columnsReact中的無狀態(tài)和有狀...
摘要:在當(dāng)前階段,僅僅只是字節(jié)碼規(guī)范。如果都沒有將代碼編譯為字節(jié)碼的工具,要起步就很困難了。接下來要做的是使用將格式的代碼轉(zhuǎn)換為二進(jìn)制碼。運(yùn)行文件,最后就能得到瀏覽器需要的真正的二進(jìn)制碼。 本文轉(zhuǎn)載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/1031原文:http://cultureofdevelopment.com/blog/build-your-fi...
摘要:本文是圖說系列文章的第五篇。這樣的話,使用的開發(fā)者也不需要做任何適配,但是它們卻能獲得更高性能。該圖并不是用來準(zhǔn)確的衡量其性能的。運(yùn)行編寫出高性能的代碼是可能的。這種清理工作由引擎自動進(jìn)行,稱為垃圾回收。 本文是圖說 WebAssembly 系列文章的第五篇。如果您還未閱讀之前的文章,建議您從第一篇入手。 在上一篇文章中,我們說到了使用 WebAssembly 和 JavaScript...
閱讀 1315·2023-04-26 01:28
閱讀 2065·2021-11-08 13:28
閱讀 2315·2021-10-12 10:17
閱讀 2280·2021-09-28 09:46
閱讀 4140·2021-09-09 09:33
閱讀 3719·2021-09-04 16:40
閱讀 1076·2019-08-29 15:21
閱讀 2689·2019-08-26 17:17