日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

跨端輕量JavaScript引擎的實現(xiàn)與探索

來源: 責(zé)編: 時間:2024-03-18 09:42:06 194觀看
導(dǎo)讀一、JavaScript1.JavaScript語言JavaScript是ECMAScript的實現(xiàn),由ECMA 39(歐洲計算機制造商協(xié)會39號技術(shù)委員會)負責(zé)制定ECMAScript標(biāo)準(zhǔn)。ECMAScript發(fā)展史:時間版本說明1997年7月ES1.0 發(fā)布當(dāng)年7月,ECMA262 標(biāo)準(zhǔn)出臺1

一、JavaScript

1.JavaScript語言

JavaScript是ECMAScript的實現(xiàn),由ECMA 39(歐洲計算機制造商協(xié)會39號技術(shù)委員會)負責(zé)制定ECMAScript標(biāo)準(zhǔn)。fJ028資訊網(wǎng)——每日最新資訊28at.com

ECMAScript發(fā)展史:fJ028資訊網(wǎng)——每日最新資訊28at.com

時間fJ028資訊網(wǎng)——每日最新資訊28at.com

版本fJ028資訊網(wǎng)——每日最新資訊28at.com

說明fJ028資訊網(wǎng)——每日最新資訊28at.com

1997年7月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES1.0 發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com

當(dāng)年7月,ECMA262 標(biāo)準(zhǔn)出臺fJ028資訊網(wǎng)——每日最新資訊28at.com

1998年6月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES2.0 發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com

該版本修改完全符合ISO/IEC 16262國際標(biāo)準(zhǔn)。fJ028資訊網(wǎng)——每日最新資訊28at.com

1999年12月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES3.0 發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com

成為 JavaScript 的通行標(biāo)準(zhǔn),得到了廣泛支持fJ028資訊網(wǎng)——每日最新資訊28at.com

2007年10月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES4.0草案發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com

各大廠商意見分歧,該方案未通過fJ028資訊網(wǎng)——每日最新資訊28at.com

2008年7月fJ028資訊網(wǎng)——每日最新資訊28at.com

發(fā)布ES3.1,并改名為ECMAScript 5fJ028資訊網(wǎng)——每日最新資訊28at.com

廢除ECMAScript 4.0,所以4.0版本不存在fJ028資訊網(wǎng)——每日最新資訊28at.com

2009年12月fJ028資訊網(wǎng)——每日最新資訊28at.com

ESt 5.0 正式發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

2011年6月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES5.1 發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com

該版本成為了 ISO 國際標(biāo)準(zhǔn)(ISO/IEC 16262:2011)fJ028資訊網(wǎng)——每日最新資訊28at.com

2013年12月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES6 草案發(fā)布fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

2015年6月fJ028資訊網(wǎng)——每日最新資訊28at.com

ES6 正式發(fā)布,并且更名為“ECMAScript 2015”fJ028資訊網(wǎng)——每日最新資訊28at.com

TC39委員會決定每年發(fā)布一個ECMAScript 的版本fJ028資訊網(wǎng)——每日最新資訊28at.com

2.JavaScript引擎

JavaScript引擎是指用于處理以及執(zhí)行JavaScript腳本的虛擬機。fJ028資訊網(wǎng)——每日最新資訊28at.com

常見的JavaScript引擎:fJ028資訊網(wǎng)——每日最新資訊28at.com

fJ028資訊網(wǎng)——每日最新資訊28at.com

引擎fJ028資訊網(wǎng)——每日最新資訊28at.com

所屬機構(gòu)/個人fJ028資訊網(wǎng)——每日最新資訊28at.com

瀏覽器fJ028資訊網(wǎng)——每日最新資訊28at.com

說明fJ028資訊網(wǎng)——每日最新資訊28at.com

SpiderMonkeyfJ028資訊網(wǎng)——每日最新資訊28at.com

MozillafJ028資訊網(wǎng)——每日最新資訊28at.com

FirefoxfJ028資訊網(wǎng)——每日最新資訊28at.com

第一款JavaScript引擎,早期用于 Netscape Navigator,現(xiàn)時用于 Mozilla Firefox。是用C語言實現(xiàn)的,還有一個Java版本叫Rhino;Rhino引擎由Mozilla基金會管理,開放源代碼,完全以Java編寫,用于 HTMLUnit;而后TraceMonkey引擎是基于實時編譯的引擎,用于Mozilla Firefox 3.5~3.6版本;JaegerMonkey:結(jié)合追蹤和組合碼技術(shù)大幅提高性能,用于Mozilla Firefox 4.0以上版本fJ028資訊網(wǎng)——每日最新資訊28at.com

JavaScriptCorefJ028資訊網(wǎng)——每日最新資訊28at.com

ApplefJ028資訊網(wǎng)——每日最新資訊28at.com

SafarifJ028資訊網(wǎng)——每日最新資訊28at.com

簡稱JSC,開源,用于webkit內(nèi)核瀏覽器,如 Safari ,2008 年實現(xiàn)了編譯器和字節(jié)碼解釋器,升級為了SquirrelFish。蘋果內(nèi)部代號為Nitro的 JavaScript 引擎也是基于 JSC引擎的。至于具體時間,JSC是WebKit默認內(nèi)嵌的JS引擎,而WebKit誕生于1998年,Nitro是為Safari 4編寫,Safari 4是2009年6月發(fā)布。fJ028資訊網(wǎng)——每日最新資訊28at.com

V8fJ028資訊網(wǎng)——每日最新資訊28at.com

GooglefJ028資訊網(wǎng)——每日最新資訊28at.com

ChromefJ028資訊網(wǎng)——每日最新資訊28at.com

2008年9月,Google的V8引擎第一個版本隨著Chrome的第一個版本發(fā)布。V8引擎用 C++編寫,由 Google 丹麥開發(fā),開源。除了Chrome,還被運用于Node.js以及運用于Android操作系統(tǒng)等fJ028資訊網(wǎng)——每日最新資訊28at.com

ChakrafJ028資訊網(wǎng)——每日最新資訊28at.com

MicrosoftfJ028資訊網(wǎng)——每日最新資訊28at.com

Edge、IEfJ028資訊網(wǎng)——每日最新資訊28at.com

譯名查克拉,用于IE9、10、11和Microsoft Edge,IE9發(fā)布時間2011年3月fJ028資訊網(wǎng)——每日最新資訊28at.com

JerryScriptfJ028資訊網(wǎng)——每日最新資訊28at.com

三星fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

三星推出的適用于嵌入式設(shè)備的小型 JavaScript 引擎,2015年開源fJ028資訊網(wǎng)——每日最新資訊28at.com

NashornfJ028資訊網(wǎng)——每日最新資訊28at.com

OracalefJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

從 JDK 1.8 開始,Nashorn取代Rhino(JDK 1.6, JDK1.7) 成為 Java 的嵌入式 JavaScript 引擎,JDK1.8發(fā)布于2014年fJ028資訊網(wǎng)——每日最新資訊28at.com

QuickJSfJ028資訊網(wǎng)——每日最新資訊28at.com

Fabrice BellardfJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

QuickJS 是一個小型的嵌入式 Javascript 引擎。 它支持 ES2023 規(guī)范,包括模塊、異步生成器、代理和 BigInt。 它可以選擇支持數(shù)學(xué)擴展,例如大十進制浮點數(shù) (BigDecimal)、大二進制浮點數(shù) (BigFloat) 和運算符重載。fJ028資訊網(wǎng)——每日最新資訊28at.com

HermesfJ028資訊網(wǎng)——每日最新資訊28at.com

FacebookfJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

引擎,F(xiàn)acebook在Chain React 2019 大會上發(fā)布的一個嶄新JavaScript引擎,用于移動端React Native應(yīng)用的集成,開源fJ028資訊網(wǎng)——每日最新資訊28at.com

3.JavaScript引擎工作原理

a.V8引擎工作原理

fJ028資訊網(wǎng)——每日最新資訊28at.com

b.Turbofan技術(shù)實例說明

function sum(a, b) {    return a + b;}

這里a和b可以是任意類型數(shù)據(jù),當(dāng)執(zhí)行sum函數(shù)時,Ignition解釋器會檢查a和b的數(shù)據(jù)類型,并相應(yīng)地執(zhí)行加法或者連接字符串的操作。fJ028資訊網(wǎng)——每日最新資訊28at.com

如果 sum函數(shù)被調(diào)用多次,每次執(zhí)行時都要檢查參數(shù)的數(shù)據(jù)類型是很浪費時間的。此時TurboFan就出場了。它會分析函數(shù)的執(zhí)行信息,如果以前每次調(diào)用sum函數(shù)時傳遞的參數(shù)類型都是數(shù)字,那么TurboFan就預(yù)設(shè)sum的參數(shù)類型是數(shù)字類型,然后將其編譯為機器碼。fJ028資訊網(wǎng)——每日最新資訊28at.com

但是如果某一次的調(diào)用傳入的參數(shù)不再是數(shù)字時,表示TurboFan的假設(shè)是錯誤的,此時優(yōu)化編譯生成的機器代碼就不能再使用了,于是就需要進行回退到字節(jié)碼的操作。fJ028資訊網(wǎng)——每日最新資訊28at.com

三、QuickJS

1.QuickJS作者簡介

法布里斯·貝拉 (Fabrice Bellard)fJ028資訊網(wǎng)——每日最新資訊28at.com

fJ028資訊網(wǎng)——每日最新資訊28at.com

fJ028資訊網(wǎng)——每日最新資訊28at.com

2.QuickJS簡介

QuickJS 是一個小型的嵌入式 Javascript 引擎。 它支持 ES2023 規(guī)范,包括模塊、異步生成器、代理和 BigInt。fJ028資訊網(wǎng)——每日最新資訊28at.com

它可以選擇支持數(shù)學(xué)擴展,例如大十進制浮點數(shù) (BigDecimal)、大二進制浮點數(shù) (BigFloat) 和運算符重載。fJ028資訊網(wǎng)——每日最新資訊28at.com

?小且易于嵌入:只需幾個 C 文件,無外部依賴項,一個簡單的 hello world 程序的 210 KiB x86 代碼。fJ028資訊網(wǎng)——每日最新資訊28at.com

?啟動時間極短的快速解釋器:在臺式 PC 的單核上運行 ECMAScript 測試套件的 76000 次測試只需不到 2 分鐘。 運行時實例的完整生命周期在不到 300 微秒的時間內(nèi)完成。fJ028資訊網(wǎng)——每日最新資訊28at.com

?幾乎完整的 ES2023 支持,包括模塊、異步生成器和完整的附錄 B 支持(舊版 Web 兼容性)。fJ028資訊網(wǎng)——每日最新資訊28at.com

?通過了近 100% 的 ECMAScript 測試套件測試: Test262 Report(https://test262.fyi/#)。fJ028資訊網(wǎng)——每日最新資訊28at.com

?可以將 Javascript 源代碼編譯為可執(zhí)行文件,無需外部依賴。fJ028資訊網(wǎng)——每日最新資訊28at.com

?使用引用計數(shù)(以減少內(nèi)存使用并具有確定性行為)和循環(huán)刪除的垃圾收集。fJ028資訊網(wǎng)——每日最新資訊28at.com

?數(shù)學(xué)擴展:BigDecimal、BigFloat、運算符重載、bigint 模式、數(shù)學(xué)模式。fJ028資訊網(wǎng)——每日最新資訊28at.com

?用 Javascript 實現(xiàn)的帶有上下文著色的命令行解釋器。fJ028資訊網(wǎng)——每日最新資訊28at.com

?帶有 C 庫包裝器的小型內(nèi)置標(biāo)準(zhǔn)庫。fJ028資訊網(wǎng)——每日最新資訊28at.com

3.QuickJS工程簡介

5.94MB quickjs├── 17.6kB      cutils.c                /// 輔助函數(shù)├── 7.58kB      cutils.h                /// 輔助函數(shù)├── 241kB       libbf.c                 /// BigFloat相關(guān)├── 17.9kB      libbf.h                 /// BigFloat相關(guān)├── 2.25kB      libregexp-opcode.h      /// 正則表達式操作符├── 82.3kB      libregexp.c             /// 正則表達式相關(guān)├── 3.26kB      libregexp.h             /// 正則表達式相關(guān)├── 3.09kB      list.h                  /// 鏈表實現(xiàn)├── 16.7kB      qjs.c                   /// QuickJS stand alone interpreter├── 22kB        qjsc.c                  /// QuickJS command line compiler├── 73.1kB      qjscalc.js              /// 數(shù)學(xué)計算器├── 7.97kB      quickjs-atom.h          /// 定義了javascript中的關(guān)鍵字├── 114kB       quickjs-libc.c├── 2.57kB      quickjs-libc.h          /// C API├── 15.9kB      quickjs-opcode.h        /// 字節(jié)碼操作符定義├── 1.81MB      quickjs.c               ├── 41.9kB      quickjs.h               /// QuickJS Engine├── 49.8kB      repl.js                 /// REPL├── 218kB       libunicode-table.h      /// unicode相關(guān)├── 53kB        libunicode.c            /// unicode相關(guān)├── 3.86kB      libunicode.h            /// unicode相關(guān)├── 86.4kB      unicode_gen.c           /// unicode相關(guān)└── 6.99kB      unicode_gen_def.h       /// unicode相關(guān)

4.QuickJS工作原理

QuickJS的解釋器是基于棧的。fJ028資訊網(wǎng)——每日最新資訊28at.com

fJ028資訊網(wǎng)——每日最新資訊28at.com

QuickJS的對byte-code會優(yōu)化兩次,通過一個簡單例子看看QuickJS的字節(jié)碼與優(yōu)化器的輸出,以及執(zhí)行過程。fJ028資訊網(wǎng)——每日最新資訊28at.com

function sum(a, b) {    return a + b;}

?第一階段(未經(jīng)過優(yōu)化的字節(jié)碼)fJ028資訊網(wǎng)——每日最新資訊28at.com

;; function sum(a, b) {        enter_scope 1    ;;     return a + b;        line_num 2        scope_get_var a,1    ///通用的獲取變量的指令        scope_get_var b,1            add        return;; }

?第二階段fJ028資訊網(wǎng)——每日最新資訊28at.com

;; function sum(a, b) {;;     return a + b;        line_num 2        get_arg 0: a        /// 獲取參數(shù)列表中的變量        get_arg 1: b        add        return;; }

?第三階段fJ028資訊網(wǎng)——每日最新資訊28at.com

;; function sum(a, b) {;;     return a + b;        get_arg0 0: a        /// 精簡成獲取參數(shù)列表中第0個參數(shù)        get_arg1 1: b        add        return;; }
sum(1,2);

通過上述簡單的函數(shù)調(diào)用,觀察sum函數(shù)調(diào)用過程中棧幀的變化,通過計算可知sum函數(shù)最棧幀大小為兩個字節(jié)fJ028資訊網(wǎng)——每日最新資訊28at.com

get_arg0fJ028資訊網(wǎng)——每日最新資訊28at.com

get_arg1fJ028資訊網(wǎng)——每日最新資訊28at.com

addfJ028資訊網(wǎng)——每日最新資訊28at.com

returnfJ028資訊網(wǎng)——每日最新資訊28at.com

1fJ028資訊網(wǎng)——每日最新資訊28at.com

2fJ028資訊網(wǎng)——每日最新資訊28at.com

3fJ028資訊網(wǎng)——每日最新資訊28at.com

將棧頂?shù)臄?shù)據(jù)3返回fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

1fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com


fJ028資訊網(wǎng)——每日最新資訊28at.com

5.內(nèi)存管理

QuickJS通過引用計算來管理內(nèi)存,在使用C API時需要根據(jù)不同API的說明手動增加或者減少引用計數(shù)器。fJ028資訊網(wǎng)——每日最新資訊28at.com

對于循環(huán)引用的對象,QuickJS通過臨時減引用保存到臨時數(shù)組中的方法來判斷相互引用的對象是否可以回收。fJ028資訊網(wǎng)——每日最新資訊28at.com

6.QuickJS簡單使用

從github上clone完最新的源碼后,通過執(zhí)行(macos 環(huán)境)以下代碼即可在本地安裝好qjs、qjsc、qjscalc幾個命令行程序fJ028資訊網(wǎng)——每日最新資訊28at.com

sudo makesudo make install

?qjs: JavaScript代碼解釋器fJ028資訊網(wǎng)——每日最新資訊28at.com

?qjsc: JavaScript代碼編譯器fJ028資訊網(wǎng)——每日最新資訊28at.com

?qjscalc: 基于QuickJS的REPL計算器程序fJ028資訊網(wǎng)——每日最新資訊28at.com

通過使用qjs可以直接運行一個JavaScript源碼,通過qsjc的如下命令,則可以輸出一個帶有byte-code源碼的可直接運行的C源文件:fJ028資訊網(wǎng)——每日最新資訊28at.com

qjsc -e  -o add.c examples/add.js
#include "quickjs-libc.h"const uint32_t qjsc_add_size = 135;const uint8_t qjsc_add[135] = { 0x02, 0x06, 0x06, 0x73, 0x75, 0x6d, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x1e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x61, 0x64, 0x64, 0x2e, 0x6a, 0x73, 0x02, 0x61, 0x02, 0x62, 0x0e, 0x00, 0x06, 0x00, 0xa2, 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x25, 0x01, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x3f, 0xe3, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x00, 0x40, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0xe5, 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, 0xb8, 0xb9, 0xf2, 0x24, 0x01, 0x00, 0xcf, 0x28, 0xcc, 0x03, 0x01, 0x04, 0x1f, 0x00, 0x08, 0x0a, 0x0e, 0x43, 0x06, 0x00, 0xc6, 0x03, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x02, 0xce, 0x03, 0x00, 0x01, 0x00, 0xd0, 0x03, 0x00, 0x01, 0x00, 0xd3, 0xd4, 0x9e, 0x28, 0xcc, 0x03, 0x01, 0x01, 0x03,};static JSContext *JS_NewCustomContext(JSRuntime *rt){  JSContext *ctx = JS_NewContextRaw(rt);  if (!ctx)    return NULL;  JS_AddIntrinsicBaseObjects(ctx);  JS_AddIntrinsicDate(ctx);  JS_AddIntrinsicEval(ctx);  JS_AddIntrinsicStringNormalize(ctx);  JS_AddIntrinsicRegExp(ctx);  JS_AddIntrinsicJSON(ctx);  JS_AddIntrinsicProxy(ctx);  JS_AddIntrinsicMapSet(ctx);  JS_AddIntrinsicTypedArrays(ctx);  JS_AddIntrinsicPromise(ctx);  JS_AddIntrinsicBigInt(ctx);  return ctx;}int main(int argc, char **argv){  JSRuntime *rt;  JSContext *ctx;  rt = JS_NewRuntime();  js_std_set_worker_new_context_func(JS_NewCustomContext);  js_std_init_handlers(rt);  JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);  ctx = JS_NewCustomContext(rt);  js_std_add_helpers(ctx, argc, argv);  js_std_eval_binary(ctx, qjsc_add, qjsc_add_size, 0);  js_std_loop(ctx);  js_std_free_handlers(rt);  JS_FreeContext(ctx);  JS_FreeRuntime(rt);  return 0;}

上面的這個C源文件,通過如下命令即可編譯成可執(zhí)行文件:fJ028資訊網(wǎng)——每日最新資訊28at.com

gcc add.c -o add_exec -I/usr/local/include quickjs-libc.c quickjs.c cutils.c libbf.c libregexp.c libunicode.c  -DCONFIG_BIGNUM

也可以直接使用如下命令,將JavaScript文件直接編譯成可執(zhí)行文件:fJ028資訊網(wǎng)——每日最新資訊28at.com

qjsc -o add_exec examples/add.js

7.給qjsc添加擴展

QuickJS只實現(xiàn)了最基本的JavaScript能力,同時QuickJS也可以實現(xiàn)能力的擴展,比如給QuickJS添加打開文件并讀取文件內(nèi)容的內(nèi)容,這樣在JavaScript代碼中即可通過js代碼打開并讀取到文件內(nèi)容了。fJ028資訊網(wǎng)——每日最新資訊28at.com

通過一個例子來看看添加擴展都需要做哪些操作:fJ028資訊網(wǎng)——每日最新資訊28at.com

?編寫一個C語言的擴展模塊fJ028資訊網(wǎng)——每日最新資訊28at.com

#include "quickjs.h"#include "cutils.h"http:/// js中對應(yīng)plus函數(shù)的C語言函數(shù)static JSValue plusNumbers(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {    int a, b;    if (JS_ToInt32(ctx, &a, argv[0]))        return JS_EXCEPTION;    if (JS_ToInt32(ctx, &b, argv[1]))        return JS_EXCEPTION;    return JS_NewInt32(ctx, a + b);}/// 模塊需要導(dǎo)致的列表static const JSCFunctionListEntry js_my_module_funcs[] = {    JS_CFUNC_DEF("plus", 2, plusNumbers),};/// 模塊初始化函數(shù),并將plus導(dǎo)出static int js_my_module_init(JSContext *ctx, JSModuleDef *m) {    return JS_SetModuleExportList(ctx, m, js_my_module_funcs, countof(js_my_module_funcs));}JSModuleDef *js_init_module_my_module(JSContext *ctx, const char *module_name) {    JSModuleDef *m;    m = JS_NewCModule(ctx, module_name, js_my_module_init);    if (!m)        return NULL;    JS_AddModuleExportList(ctx, m, js_my_module_funcs, countof(js_my_module_funcs));    return m;}

?Makefile文件中添加my_module.c模塊的編譯fJ028資訊網(wǎng)——每日最新資訊28at.com

QJS_LIB_OBJS= ... $(OBJDIR)/my_module.o

?在qjsc.c文件中注冊模塊fJ028資訊網(wǎng)——每日最新資訊28at.com

namelist_add(&cmodule_list,“my_module”,“my_module”,0);

?編寫一個my_module.js測試文件fJ028資訊網(wǎng)——每日最新資訊28at.com

import * as mm from 'my_module';const value = mm.plus(1, 2);console.log(`my_module.plus: ${value}`);

?重新編譯fJ028資訊網(wǎng)——每日最新資訊28at.com

sudo make && sudo make installqjsc -m -o my_module examples/my_module.js /// 這里需要指定my_module模塊

最終生成的my_module可執(zhí)行文件,通過執(zhí)行my_module輸出:fJ028資訊網(wǎng)——每日最新資訊28at.com

my_module.plus: 3

8.使用C API

在第5個步驟時,生成了add.c文件中實際上已經(jīng)給出了一個簡單的使用C API最基本的代碼。當(dāng)編寫一下如下的js源碼時,會發(fā)現(xiàn)當(dāng)前的qjsc編譯后的可執(zhí)行文件或者qjs執(zhí)行這段js代碼與我們的預(yù)期不符:fJ028資訊網(wǎng)——每日最新資訊28at.com

function getName() {    return new Promise((resolve, reject) => {        setTimeout(() => {            resolve("張三峰");        }, 2000);    });}console.log(`開始執(zhí)行`);getName().then(name => console.log(`promise name: ${name}`));

fJ028資訊網(wǎng)——每日最新資訊28at.com

上面的代碼并不會按預(yù)期的效果輸出結(jié)果,因為js環(huán)境下的loop只執(zhí)行了一次,任務(wù)隊列還沒有來得急執(zhí)行程序就結(jié)束了,稍微改動一下讓程序可以正常輸出,如下:fJ028資訊網(wǎng)——每日最新資訊28at.com

#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <uv.h>/* File generated automatically by the QuickJS compiler. */#include "quickjs-libc.h"#include <string.h>static JSContext *JS_NewCustomContext(JSRuntime *rt) {  JSContext *ctx = JS_NewContextRaw(rt);  if (!ctx)    return NULL;  JS_AddIntrinsicBaseObjects(ctx);  JS_AddIntrinsicDate(ctx);  JS_AddIntrinsicEval(ctx);  JS_AddIntrinsicStringNormalize(ctx);  JS_AddIntrinsicRegExp(ctx);  JS_AddIntrinsicJSON(ctx);  JS_AddIntrinsicProxy(ctx);  JS_AddIntrinsicMapSet(ctx);  JS_AddIntrinsicTypedArrays(ctx);  JS_AddIntrinsicPromise(ctx);  JS_AddIntrinsicBigInt(ctx);  return ctx;}JSRuntime *rt = NULL;JSContext *ctx = NULL;void *run(void *args) {    const char *file_path = "/Volumes/Work/分享/quickjs/code/quickjs/examples/promise.js";    size_t pbuf_len = 0;            js_std_set_worker_new_context_func(JS_NewCustomContext);    js_std_init_handlers(rt);    JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);    ctx = JS_NewCustomContext(rt);            js_std_add_helpers(ctx, 0, NULL);    js_init_module_os(ctx, "test");    const uint8_t *code = js_load_file(ctx, &pbuf_len, file_path);    JSValue js_ret_val = JS_Eval(ctx, (char *)code, pbuf_len, "add", JS_EVAL_TYPE_MODULE);    if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {        js_std_dump_error(ctx);    }    return NULL;}pthread_t quickjs_t;int main(int argc, char **argv) {    rt = JS_NewRuntime();    pthread_create(&quickjs_t, NULL, run, NULL);    while (1) {        if(ctx) js_std_loop(ctx);    }    js_std_free_handlers(rt);    JS_FreeContext(ctx);    JS_FreeRuntime(rt);    return 0;}

這樣的操作只適合用于測試一下功能,實際生產(chǎn)中使用需要一個即可以在必要的時候調(diào)用loop又可以做到不搶占過多的CPU或者只搶占較少的CPU時間片。fJ028資訊網(wǎng)——每日最新資訊28at.com

四、libuv

1.libuv簡價

libuv 是一個使用C語言編寫的多平臺支持庫,專注于異步 I/O。 它主要是為 Node.js 使用而開發(fā)的,但 Luvit、Julia、uvloop 等也使用它。fJ028資訊網(wǎng)——每日最新資訊28at.com

功能亮點fJ028資訊網(wǎng)——每日最新資訊28at.com

?由 epoll、kqueue、IOCP、事件端口支持的全功能事件循環(huán)。fJ028資訊網(wǎng)——每日最新資訊28at.com

?異步 TCP 和 UDP 套接字fJ028資訊網(wǎng)——每日最新資訊28at.com

?異步 DNS 解析fJ028資訊網(wǎng)——每日最新資訊28at.com

?異步文件和文件系統(tǒng)操作fJ028資訊網(wǎng)——每日最新資訊28at.com

?文件系統(tǒng)事件fJ028資訊網(wǎng)——每日最新資訊28at.com

?ANSI 轉(zhuǎn)義碼控制的 TTYfJ028資訊網(wǎng)——每日最新資訊28at.com

?具有套接字共享的 IPC,使用 Unix 域套接字或命名管道 (Windows)fJ028資訊網(wǎng)——每日最新資訊28at.com

?子進程fJ028資訊網(wǎng)——每日最新資訊28at.com

?線程池fJ028資訊網(wǎng)——每日最新資訊28at.com

?信號處理fJ028資訊網(wǎng)——每日最新資訊28at.com

?高分辨率時鐘fJ028資訊網(wǎng)——每日最新資訊28at.com

?線程和同步原語fJ028資訊網(wǎng)——每日最新資訊28at.com

2.libuv運行原理

fJ028資訊網(wǎng)——每日最新資訊28at.com

int uv_run(uv_loop_t* loop, uv_run_mode mode) {  ...  r = uv__loop_alive(loop);  if (!r)    uv__update_time(loop);  while (r != 0 && loop->stop_flag == 0) {    uv__update_time(loop);    uv__run_timers(loop);    ran_pending = uv__run_pending(loop);    uv__run_idle(loop);    uv__run_prepare(loop);    ...    uv__io_poll(loop, timeout);    uv__run_check(loop);    uv__run_closing_handles(loop);    ...  }}

3.簡單使用

static void timer_cb(uv_timer_t *handler) {    printf("timer_cb exec./r/n");}int main(int argc, const char * argv[]) {   uv_loop_t *loop = uv_default_loop();   uv_timer_t *timer = (uv_timer_t*)malloc(sizeof(uv_timer_t));   uv_timer_init(loop, timer);   uv_timer_start(timer, timer_cb, 2000, 0);   uv_run(loop, UV_RUN_DEFAULT);}

五、QuickJS + libuv

console.log(`開始執(zhí)行`);function getName() {    return new Promise((resolve, reject) => {        setTimeout(() => {            resolve("張三峰");        }, 2000);    });}getName().then(name => console.log(`promise name: ${name}`));

fJ028資訊網(wǎng)——每日最新資訊28at.com

#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <uv.h>/* File generated automatically by the QuickJS compiler. */#include "quickjs-libc.h"#include <string.h>typedef struct once_timer_data {    JSValue func;    JSValue this_val;    JSContext *ctx;} once_timer_data;void once_timer_cb(uv_timer_t *once_timer) {    once_timer_data *data = (once_timer_data *)once_timer->data;    JSContext *ctx = data->ctx;    JSValue js_ret_val = JS_Call(data->ctx, data->func, data->this_val, 0, NULL);    if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {        js_std_dump_error(ctx);    }    JS_FreeValue(data->ctx, js_ret_val);    JS_FreeValue(data->ctx, data->func);    JS_FreeValue(data->ctx, data->this_val);    free(data);    uv_timer_stop(once_timer);    free(once_timer);}void check_cb(uv_check_t *check) {    JSContext *ctx = (JSContext *)check->data;    js_std_loop(ctx);}void idle_cb(uv_idle_t *idle) {    }JSValue set_timeout(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {     if(argc != 2) return JS_NULL;    JSValue func_val = argv[0];    JSValue delay_val = argv[1];    int64_t delay = 0;    int ret = JS_ToInt64(ctx, &delay, delay_val);    if(ret < 0) js_std_dump_error(ctx);    uv_timer_t *once_timer = (uv_timer_t *)malloc(sizeof(uv_timer_t));    once_timer_data *data = (once_timer_data *)malloc(sizeof(once_timer_data));    data->func = JS_DupValue(ctx, func_val);    data->this_val = JS_DupValue(ctx, this_val);    data->ctx = ctx;    once_timer->data = data;    uv_timer_init(uv_default_loop(), once_timer);    uv_timer_start(once_timer, once_timer_cb, delay, 0);    JSValue js_timer = JS_NewInt64(ctx, (uint64_t)once_timer);    return js_timer;}static JSContext *JS_NewCustomContext(JSRuntime *rt) {  JSContext *ctx = JS_NewContextRaw(rt);  if (!ctx)    return NULL;  JS_AddIntrinsicBaseObjects(ctx);  JS_AddIntrinsicDate(ctx);  JS_AddIntrinsicEval(ctx);  JS_AddIntrinsicStringNormalize(ctx);  JS_AddIntrinsicRegExp(ctx);  JS_AddIntrinsicJSON(ctx);  JS_AddIntrinsicProxy(ctx);  JS_AddIntrinsicMapSet(ctx);  JS_AddIntrinsicTypedArrays(ctx);  JS_AddIntrinsicPromise(ctx);  JS_AddIntrinsicBigInt(ctx);  return ctx;}void js_job(uv_timer_t *timer) {    JSRuntime *rt = timer->data;    const char *file_path = "/Volumes/Work/分享/quickjs/code/quickjs/examples/promise.js";    size_t pbuf_len = 0;        JSContext *ctx;    js_std_set_worker_new_context_func(JS_NewCustomContext);    js_std_init_handlers(rt);    JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);    ctx = JS_NewCustomContext(rt);        uv_check_t *check = (uv_check_t *)malloc(sizeof(uv_check_t));    uv_check_init(uv_default_loop(), check);    check->data = ctx;    uv_check_start(check, check_cb);        JSValue global = JS_GetGlobalObject(ctx);    JSValue func_val = JS_NewCFunction(ctx, set_timeout, "setTimeout", 1);    JS_SetPropertyStr(ctx, global, "setTimeout", func_val);    JS_FreeValue(ctx, global);            js_std_add_helpers(ctx, 0, NULL);    js_init_module_os(ctx, "test");    const uint8_t *code = js_load_file(ctx, &pbuf_len, file_path);    JSValue js_ret_val = JS_Eval(ctx, (char *)code, pbuf_len, "add", JS_EVAL_TYPE_MODULE);    if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {        js_std_dump_error(ctx);    }    js_std_free_handlers(rt);    JS_FreeContext(ctx);  }int main(int argc, char **argv) {    JSRuntime *rt = JS_NewRuntime();    uv_loop_t *loop = uv_default_loop();        uv_timer_t *timer = (uv_timer_t*)malloc(sizeof(uv_timer_t));    timer->data = rt;    uv_timer_init(loop, timer);    uv_timer_start(timer, js_job, 0, 0);        uv_idle_t *idle = (uv_idle_t *)malloc(sizeof(uv_idle_t));    uv_idle_init(loop, idle);    uv_idle_start(idle, idle_cb);    uv_run(loop, UV_RUN_DEFAULT);    JS_FreeRuntime(rt);    return 0;}

本文鏈接:http://www.www897cc.com/showinfo-26-76532-0.html跨端輕量JavaScript引擎的實現(xiàn)與探索

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: ?2024年保護微服務(wù)的前十種技術(shù)

下一篇: .NET Core 上傳文件到本地服務(wù)器技術(shù)詳解

標(biāo)簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 鸡西市| 建平县| 邓州市| 浦城县| 闸北区| 乐安县| 郑州市| 永泰县| 宣城市| 阿巴嘎旗| 绿春县| 伊春市| 洛川县| 宁波市| 五台县| 乡城县| 吉安县| 子洲县| 托克托县| 蒙山县| 汾西县| 鹰潭市| 威远县| 西宁市| 香港| 灵川县| 和龙市| 紫金县| 潼关县| 普安县| 临沧市| 洞口县| 海阳市| 珲春市| 阳新县| 深州市| 广水市| 岚皋县| 临漳县| 顺平县| 冕宁县|