精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

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

開發(fā) 前端
libuv 是一個使用C語言編寫的多平臺支持庫,專注于異步 I/O。 它主要是為 Node.js 使用而開發(fā)的,但 Luvit、Julia、uvloop 等也使用它。

一、JavaScript

1.JavaScript語言

JavaScript是ECMAScript的實現(xiàn),由ECMA 39(歐洲計算機制造商協(xié)會39號技術(shù)委員會)負責(zé)制定ECMAScript標準。

ECMAScript發(fā)展史:

時間

版本

說明

1997年7月

ES1.0 發(fā)布

當(dāng)年7月,ECMA262 標準出臺

1998年6月

ES2.0 發(fā)布

該版本修改完全符合ISO/IEC 16262國際標準。

1999年12月

ES3.0 發(fā)布

成為 JavaScript 的通行標準,得到了廣泛支持

2007年10月

ES4.0草案發(fā)布

各大廠商意見分歧,該方案未通過

2008年7月

發(fā)布ES3.1,并改名為ECMAScript 5

廢除ECMAScript 4.0,所以4.0版本不存在

2009年12月

ESt 5.0 正式發(fā)布


2011年6月

ES5.1 發(fā)布

該版本成為了 ISO 國際標準(ISO/IEC 16262:2011)

2013年12月

ES6 草案發(fā)布


2015年6月

ES6 正式發(fā)布,并且更名為“ECMAScript 2015”

TC39委員會決定每年發(fā)布一個ECMAScript 的版本

2.JavaScript引擎

JavaScript引擎是指用于處理以及執(zhí)行JavaScript腳本的虛擬機。

常見的JavaScript引擎:

引擎

所屬機構(gòu)/個人

瀏覽器

說明

SpiderMonkey

Mozilla

Firefox

第一款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以上版本

JavaScriptCore

Apple

Safari

簡稱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ā)布。

V8

Google

Chrome

2008年9月,Google的V8引擎第一個版本隨著Chrome的第一個版本發(fā)布。V8引擎用 C++編寫,由 Google 丹麥開發(fā),開源。除了Chrome,還被運用于Node.js以及運用于Android操作系統(tǒng)等

Chakra

Microsoft

Edge、IE

譯名查克拉,用于IE9、10、11和Microsoft Edge,IE9發(fā)布時間2011年3月

JerryScript

三星


三星推出的適用于嵌入式設(shè)備的小型 JavaScript 引擎,2015年開源

Nashorn

Oracale


從 JDK 1.8 開始,Nashorn取代Rhino(JDK 1.6, JDK1.7) 成為 Java 的嵌入式 JavaScript 引擎,JDK1.8發(fā)布于2014年

QuickJS

Fabrice Bellard


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

Hermes

Facebook


引擎,F(xiàn)acebook在Chain React 2019 大會上發(fā)布的一個嶄新JavaScript引擎,用于移動端React Native應(yīng)用的集成,開源

3.JavaScript引擎工作原理

a.V8引擎工作原理

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í)行加法或者連接字符串的操作。

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

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

三、QuickJS

1.QuickJS作者簡介

法布里斯·貝拉 (Fabrice Bellard)

2.QuickJS簡介

QuickJS 是一個小型的嵌入式 Javascript 引擎。 它支持 ES2023 規(guī)范,包括模塊、異步生成器、代理和 BigInt。

它可以選擇支持數(shù)學(xué)擴展,例如大十進制浮點數(shù) (BigDecimal)、大二進制浮點數(shù) (BigFloat) 和運算符重載。

?小且易于嵌入:只需幾個 C 文件,無外部依賴項,一個簡單的 hello world 程序的 210 KiB x86 代碼。

?啟動時間極短的快速解釋器:在臺式 PC 的單核上運行 ECMAScript 測試套件的 76000 次測試只需不到 2 分鐘。 運行時實例的完整生命周期在不到 300 微秒的時間內(nèi)完成。

?幾乎完整的 ES2023 支持,包括模塊、異步生成器和完整的附錄 B 支持(舊版 Web 兼容性)。

?通過了近 100% 的 ECMAScript 測試套件測試: Test262 Report(https://test262.fyi/#)。

?可以將 Javascript 源代碼編譯為可執(zhí)行文件,無需外部依賴。

?使用引用計數(shù)(以減少內(nèi)存使用并具有確定性行為)和循環(huán)刪除的垃圾收集。

?數(shù)學(xué)擴展:BigDecimal、BigFloat、運算符重載、bigint 模式、數(shù)學(xué)模式。

?用 Javascript 實現(xiàn)的帶有上下文著色的命令行解釋器。

?帶有 C 庫包裝器的小型內(nèi)置標準庫。

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的解釋器是基于棧的。

QuickJS的對byte-code會優(yōu)化兩次,通過一個簡單例子看看QuickJS的字節(jié)碼與優(yōu)化器的輸出,以及執(zhí)行過程。

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

?第一階段(未經(jīng)過優(yōu)化的字節(jié)碼)

;; 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

;; }

?第二階段

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

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

?第三階段

;; 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é)

get_arg0

get_arg1

add

return

1

2

3

將棧頂?shù)臄?shù)據(jù)3返回


1



5.內(nèi)存管理

QuickJS通過引用計算來管理內(nèi)存,在使用C API時需要根據(jù)不同API的說明手動增加或者減少引用計數(shù)器。

對于循環(huán)引用的對象,QuickJS通過臨時減引用保存到臨時數(shù)組中的方法來判斷相互引用的對象是否可以回收。

6.QuickJS簡單使用

從github上clone完最新的源碼后,通過執(zhí)行(macos 環(huán)境)以下代碼即可在本地安裝好qjs、qjsc、qjscalc幾個命令行程序

sudo make
sudo make install

?qjs: JavaScript代碼解釋器

?qjsc: JavaScript代碼編譯器

?qjscalc: 基于QuickJS的REPL計算器程序

通過使用qjs可以直接運行一個JavaScript源碼,通過qsjc的如下命令,則可以輸出一個帶有byte-code源碼的可直接運行的C源文件:

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í)行文件:

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í)行文件:

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)容了。

通過一個例子來看看添加擴展都需要做哪些操作:

?編寫一個C語言的擴展模塊

#include "quickjs.h"
#include "cutils.h"

/// 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模塊的編譯

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

?在qjsc.c文件中注冊模塊

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

?編寫一個my_module.js測試文件

import * as mm from 'my_module';

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

?重新編譯

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

最終生成的my_module可執(zhí)行文件,通過執(zhí)行my_module輸出:

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ù)期不符:

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

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

#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時間片。

四、libuv

1.libuv簡價

libuv 是一個使用C語言編寫的多平臺支持庫,專注于異步 I/O。 它主要是為 Node.js 使用而開發(fā)的,但 Luvit、Julia、uvloop 等也使用它。

功能亮點

?由 epoll、kqueue、IOCP、事件端口支持的全功能事件循環(huán)。

?異步 TCP 和 UDP 套接字

?異步 DNS 解析

?異步文件和文件系統(tǒng)操作

?文件系統(tǒng)事件

?ANSI 轉(zhuǎn)義碼控制的 TTY

?具有套接字共享的 IPC,使用 Unix 域套接字或命名管道 (Windows)

?子進程

?線程池

?信號處理

?高分辨率時鐘

?線程和同步原語

2.libuv運行原理

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}`));

#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;
}
責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2023-10-31 18:32:26

WebRTC存儲

2021-05-27 05:22:28

前端引擎平臺

2022-08-06 08:34:04

京東App適配技術(shù)棧

2021-08-26 05:27:57

Swift 監(jiān)聽系統(tǒng)泛型

2023-12-13 13:15:13

平臺開發(fā)實踐

2009-06-09 21:59:13

語法高亮Javascript

2019-11-26 09:42:36

代碼開發(fā)API

2024-04-30 09:53:12

axios架構(gòu)適配器

2022-02-24 18:51:04

跨端框架方案

2024-05-15 18:59:01

JavaScript語言原型

2025-06-11 02:30:00

2024-09-23 19:53:27

數(shù)據(jù)飛輪數(shù)據(jù)驅(qū)動數(shù)字化轉(zhuǎn)型

2023-07-03 07:42:42

2024-01-08 08:23:08

OpenCV機器學(xué)習(xí)計算機視覺

2022-04-15 14:31:02

鴻蒙操作系統(tǒng)

2020-10-09 09:21:45

鴻蒙

2023-07-26 11:22:44

騰訊趙裕

2022-09-12 07:17:20

redis命令redissynce

2022-11-30 15:15:48

點贊
收藏

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

亚洲精品一区二区三区蜜桃下载 | 国产一区二区片| 国产精品第6页| 久久精品国产99久久| 欧美性受xxxx黑人xyx| 在线视频亚洲自拍| 欧美性猛交 xxxx| 久久久亚洲一区| 精品久久久av| www.555国产精品免费| 欧美成人h版| 成人欧美一区二区三区小说| 99在线首页视频| 国产日本欧美在线| а√天堂资源在线| 男人的天堂亚洲在线| 丝袜亚洲欧美日韩综合| 性欧美在线视频| 色婷婷av在线| 99精品视频在线播放观看| 欧美性受xxxx黑人猛交| 日韩女同一区二区三区| 国产欧美88| 五月激情六月综合| 日韩在线电影一区| av中文字幕第一页| 性一交一乱一区二区洋洋av| 中文字幕欧美精品在线| 在线观看的毛片| 欧美精品videossex少妇| 久久人人爽爽爽人久久久| 成人网在线免费观看| 亚洲欧美在线视频免费| 欧洲vs亚洲vs国产| 91精品办公室少妇高潮对白| 日韩a级在线观看| 高清性色生活片在线观看| 精品午夜久久福利影院| 久久久久久网址| 91视频免费看片| 久久草在线视频| 欧美精品视频www在线观看| 国产日韩欧美精品在线观看| 成a人v在线播放| www.色精品| 国产精品综合久久久| 香蕉视频一区二区| 色男人天堂综合再现| 亚洲精品av在线| 99日在线视频| 性欧美videohd高精| 亚洲成人777| 国产对白在线播放| a天堂中文在线| 2欧美一区二区三区在线观看视频 337p粉嫩大胆噜噜噜噜噜91av | 欧美激情亚洲另类| 国产一区在线观看免费| 51社区在线成人免费视频| 欧美男人的天堂一二区| 老司机午夜av| 国内精彩免费自拍视频在线观看网址 | 亚洲国产又黄又爽女人高潮的| 777一区二区| 在线观看精品| 日韩欧美在线网址| 国产中文字幕二区| 日本片在线看| 亚洲精品国产第一综合99久久| 午夜精品一区二区三区四区| 免费国产在线视频| 97aⅴ精品视频一二三区| 99久久无色码| 99热这里是精品| 精品午夜一区二区三区在线观看| 国产精品视频自拍| 免费一级a毛片| 丝袜诱惑制服诱惑色一区在线观看| 韩国19禁主播vip福利视频| 男人的天堂久久久| 欧美激情成人在线| 欧美情侣性视频| 欧美日韩亚洲国产另类| 欧美国产免费| 九九热r在线视频精品| 国产黄色片在线免费观看| 一区二区三区午夜探花| 日韩性xxxx爱| 亚洲欧美卡通动漫| 激情丁香综合| 97超级碰碰碰| 久久久蜜桃一区二区| 久久亚洲不卡| 日韩av黄色在线观看| 在线免费一区二区| 久久精品国产77777蜜臀| 成人天堂噜噜噜| 国产丝袜在线视频| 高清在线观看日韩| 精品视频一区二区| 国家队第一季免费高清在线观看| 久久久精品影视| 日本高清不卡一区二区三| 北条麻妃在线| 亚洲精品视频在线看| 妞干网视频在线观看| 99爱在线视频| 欧美综合色免费| 欧美一级xxxx| caoporn成人| 亚洲精品国产精品国自产在线 | 天天操天天爽天天干| 久久亚洲不卡| 亚洲一区二区三区在线视频| 囯产精品一品二区三区| 91香蕉视频污在线| 一区二区国产日产| caoporn97在线视频| 天天操天天色综合| 国产一二三四在线视频| 日本一区影院| 亚洲欧美日韩久久久久久| 综合 欧美 亚洲日本| 国产尤物精品| 国产精品白丝jk喷水视频一区| 亚洲网站在线免费观看| 成人高清在线视频| 亚洲成人18| 高清电影在线免费观看| 欧美视频在线不卡| 欧美夫妇交换xxx| 成人同人动漫免费观看| 欧美激情精品久久久久久变态| 黄色在线视频网址| 国产+成+人+亚洲欧洲自线| 亚洲国产精品久久久久婷婷老年| 国产区美女在线| 欧美日韩免费不卡视频一区二区三区| 在线观看成人动漫| 91亚洲自偷观看高清| 欧美孕妇与黑人孕交| 国产人妖一区二区| 国产欧美日韩中文久久| 成人免费视频91| 成人污污视频| 国产午夜精品免费一区二区三区| 久久久久亚洲av片无码下载蜜桃| 秋霞电影一区二区| 国产一区免费视频| 男女啪啪在线观看| 欧美日韩亚洲视频| 美女露出粉嫩尿囗让男人桶| 国产日产精品一区二区三区四区的观看方式| 欧美成人精品在线观看| 国产成人精品777777| 国产中文字幕精品| 视频一区二区精品| 超碰aⅴ人人做人人爽欧美| 日韩欧美高清一区| 四虎影院中文字幕| 日本va欧美va精品| 日本成人黄色| 久久91导航| 亚洲女成人图区| 日本视频www| 国产成人免费在线观看| 欧美另类videos| 亚洲一区有码| 最新亚洲国产精品| 中文字幕激情视频| 国产亚洲福利社区一区| 欧美aⅴ在线观看| 欧美精品中文字幕亚洲专区| 国内成人精品一区| www.狠狠干| 亚洲最大成人网4388xx| 91丨porny丨九色| 欧美激情四色| 成人av网站观看| 亚洲大胆人体大胆做受1| 日韩一级免费观看| 欧美三根一起进三p| 国产精品18久久久久久vr| 欧美与动交zoz0z| 欧美a在线观看| 久99久在线视频| 亚洲毛片欧洲毛片国产一品色| 一区二区高清在线| 免费日本黄色网址| 性一交一乱一区二区洋洋av| 日本电影一区二区三区| 国产精品亲子伦av一区二区三区| 最近更新的2019中文字幕| 一级做a爱片性色毛片| 亚洲色图欧美在线| 不许穿内裤随时挨c调教h苏绵 | 亚洲精品中字| 成人日韩视频| 国内精品模特av私拍在线观看| 婷婷五月综合激情| 91成人免费电影| 国产精品久久久免费看| 国产乱子轮精品视频| 无码中文字幕色专区| 欧美黄色影院| 国产精品扒开腿做| 欧洲不卡av| 亚洲第一精品自拍| 午夜一区二区三区四区| 亚洲免费看黄网站| 中国美女乱淫免费看视频| 日韩av在线免费观看不卡| 中文字幕の友人北条麻妃| 秋霞综合在线视频| 国产剧情日韩欧美| 丁香花在线高清完整版视频| 国产婷婷色综合av蜜臀av| 亚洲天堂网在线观看视频| 亚洲一级不卡视频| 国产亚洲精品熟女国产成人| 国产精品资源站在线| 亚洲精品无码久久久久久| 日韩一区电影| 精品毛片久久久久久| 精品久久在线| 午夜精品久久久久久久久久久久久 | 蜜桃狠狠色伊人亚洲综合网站| www.久久| 91po在线观看91精品国产性色| av大片在线观看| 精品精品欲导航| 最新国产中文字幕| 精品福利在线观看| 男人的天堂久久久| 欧美韩国日本不卡| 亚洲av无码一区二区三区网址| 日本不卡123| 日韩精品视频久久| 欧美精品一级| 亚洲一区二区三区欧美| 日韩欧美天堂| 丁香婷婷久久久综合精品国产| 欧美日韩五区| 91wwwcom在线观看| 手机电影在线观看| 日韩一区二区av| 色婷婷激情五月| 欧美网站大全在线观看| 精品午夜福利在线观看| 国产精品美女久久久久久久| 中文字幕一区二区三区人妻不卡| 国产成人自拍网| 久久久久久久高清| 麻豆精品在线看| 国产视频在线视频| 免费永久网站黄欧美| 欧美男女爱爱视频| 综合av在线| 在线国产精品网| 欧美亚洲在线日韩| 欧美一区2区三区4区公司二百| 超碰在线成人| av日韩中文字幕| 成人黄色视屏网站| 日韩美女av在线免费观看| 新版的欧美在线视频| 97视频com| а√天堂中文资源在线bt| 欧美激情第99页| 国产精品一区hongkong| 九九热精品视频在线播放| 亚洲91av| 欧美激情一区二区三区久久久 | 中日韩一级黄色片| 国产精品国产三级国产普通话三级| 蜜桃无码一区二区三区| 国产性做久久久久久| 一级肉体全黄裸片| 91日韩精品一区| 欧亚乱熟女一区二区在线| 99久久综合色| 国产呦小j女精品视频| 久久久99久久| 精品国产aaa| 亚洲欧洲www| 欧美成人免费看| 一区二区三区久久久| 精品无码m3u8在线观看| 亚洲电影一区二区三区| 久久狠狠高潮亚洲精品| 91九色最新地址| 在线观看免费视频a| 欧美欧美欧美欧美| www.狠狠干| 日韩精品亚洲精品| a黄色在线观看| 日韩在线观看你懂的| 日本一级理论片在线大全| 午夜精品一区二区三区在线视 | 日韩av电影手机在线| 婷婷久久免费视频| 91最新在线免费观看| 久久精品九色| 国产91精品一区二区绿帽| 欧美美乳视频| 在线精品亚洲一区二区| 好看的日韩av电影| 国产xxxxx视频| 国产酒店精品激情| 一级做a爰片毛片| 国产精品视频线看| 免费人成年激情视频在线观看| 精品毛片三在线观看| 91福利免费视频| 亚洲国产成人精品女人久久久 | 色天天色综合| 一区二区欧美日韩| 在线精品亚洲| 日本特黄a级片| 日韩亚洲在线视频| 国内外成人在线| 亚洲成人av免费观看| 久久久一区二区三区捆绑**| 精品少妇一区二区三区密爱| 香蕉av福利精品导航| 国产又粗又黄又爽视频| 亚洲精品国产精品乱码不99按摩| 黄网页在线观看| 日本久久亚洲电影| 青草伊人久久| 亚洲免费不卡| 国产亚洲福利| 国产高清av片| 久久久精品欧美丰满| 久草资源在线视频| 欧美日本在线视频| 免费人成黄页在线观看忧物| 欧美激情免费看| 亚洲精品粉嫩美女一区| 99国产视频在线| 天天做天天爱天天爽综合网| 国产第一页视频| 丁香婷婷深情五月亚洲| 欧美爱爱免费视频| 日本韩国欧美在线| 天天干天天插天天操| 欧美精品情趣视频| 欧美综合影院| 日韩高清国产一区在线观看| 亚洲色诱最新| 日本天堂在线播放| 亚洲人亚洲人成电影网站色| 欧美一级黄视频| 国产一区二区成人| 中文在线8资源库| 91视频最新| 成人综合一区| 国语对白做受xxxxx在线中国| 国产aⅴ综合色| 国产三级黄色片| 91久久线看在观草草青青| 青青草免费在线| 97免费中文视频在线观看| 超碰地址久久| 日韩一级性生活片| 成人污视频在线观看| 久久这里只有精品免费| 欧美大胆人体bbbb| 黄污视频在线观看| 国产精品乱码视频| 亚洲免费播放| 第一页在线视频| 亚洲福利视频导航| 黄色片一区二区| 午夜免费日韩视频| 婷婷国产精品| 成人羞羞国产免费网站| 久久免费看少妇高潮| 91久久国产综合久久91| 亚洲香蕉成视频在线观看| 国产伦精品一区二区三区视频金莲| 免费成人看片网址| 麻豆久久婷婷| mm131丰满少妇人体欣赏图| 在线视频观看一区| 精精国产xxxx视频在线| 亚洲一区亚洲二区| 激情综合视频| 在线中文字日产幕| 一本一道久久a久久精品| 国产美女视频一区二区三区| 国产精品视频最多的网站| 中文字幕一区二区三区在线视频| 91精产国品一二三| 黄网站色欧美视频| 日韩午夜影院| 国产区精品视频| 欧美阿v一级看视频| 人妻少妇精品视频一区二区三区| 色哟哟欧美精品| 黄色免费网站在线观看|