自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

開(kāi)發(fā) 前端
libuv 是一個(gè)使用C語(yǔ)言編寫(xiě)的多平臺(tái)支持庫(kù),專(zhuān)注于異步 I/O。 它主要是為 Node.js 使用而開(kāi)發(fā)的,但 Luvit、Julia、uvloop 等也使用它。

一、JavaScript

1.JavaScript語(yǔ)言

JavaScript是ECMAScript的實(shí)現(xiàn),由ECMA 39(歐洲計(jì)算機(jī)制造商協(xié)會(huì)39號(hào)技術(shù)委員會(huì))負(fù)責(zé)制定ECMAScript標(biāo)準(zhǔn)。

ECMAScript發(fā)展史:

時(shí)間

版本

說(shuō)明

1997年7月

ES1.0 發(fā)布

當(dāng)年7月,ECMA262 標(biāo)準(zhǔn)出臺(tái)

1998年6月

ES2.0 發(fā)布

該版本修改完全符合ISO/IEC 16262國(guó)際標(biāo)準(zhǔn)。

1999年12月

ES3.0 發(fā)布

成為 JavaScript 的通行標(biāo)準(zhǔn),得到了廣泛支持

2007年10月

ES4.0草案發(fā)布

各大廠商意見(jiàn)分歧,該方案未通過(guò)

2008年7月

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

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

2009年12月

ESt 5.0 正式發(fā)布


2011年6月

ES5.1 發(fā)布

該版本成為了 ISO 國(guó)際標(biāo)準(zhǔn)(ISO/IEC 16262:2011)

2013年12月

ES6 草案發(fā)布


2015年6月

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

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

2.JavaScript引擎

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

常見(jiàn)的JavaScript引擎:

引擎

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

瀏覽器

說(shuō)明

SpiderMonkey

Mozilla

Firefox

第一款JavaScript引擎,早期用于 Netscape Navigator,現(xiàn)時(shí)用于 Mozilla Firefox。是用C語(yǔ)言實(shí)現(xiàn)的,還有一個(gè)Java版本叫Rhino;Rhino引擎由Mozilla基金會(huì)管理,開(kāi)放源代碼,完全以Java編寫(xiě),用于 HTMLUnit;而后TraceMonkey引擎是基于實(shí)時(shí)編譯的引擎,用于Mozilla Firefox 3.5~3.6版本;JaegerMonkey:結(jié)合追蹤和組合碼技術(shù)大幅提高性能,用于Mozilla Firefox 4.0以上版本

JavaScriptCore

Apple

Safari

簡(jiǎn)稱(chēng)JSC,開(kāi)源,用于webkit內(nèi)核瀏覽器,如 Safari ,2008 年實(shí)現(xiàn)了編譯器和字節(jié)碼解釋器,升級(jí)為了SquirrelFish。蘋(píng)果內(nèi)部代號(hào)為Nitro的 JavaScript 引擎也是基于 JSC引擎的。至于具體時(shí)間,JSC是WebKit默認(rèn)內(nèi)嵌的JS引擎,而WebKit誕生于1998年,Nitro是為Safari 4編寫(xiě),Safari 4是2009年6月發(fā)布。

V8

Google

Chrome

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

Chakra

Microsoft

Edge、IE

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

JerryScript

三星


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

Nashorn

Oracale


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

QuickJS

Fabrice Bellard


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

Hermes

Facebook


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

3.JavaScript引擎工作原理

a.V8引擎工作原理

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

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

這里a和b可以是任意類(lèi)型數(shù)據(jù),當(dāng)執(zhí)行sum函數(shù)時(shí),Ignition解釋器會(huì)檢查a和b的數(shù)據(jù)類(lèi)型,并相應(yīng)地執(zhí)行加法或者連接字符串的操作。

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

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

三、QuickJS

1.QuickJS作者簡(jiǎn)介

法布里斯·貝拉 (Fabrice Bellard)

2.QuickJS簡(jiǎn)介

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

它可以選擇支持?jǐn)?shù)學(xué)擴(kuò)展,例如大十進(jìn)制浮點(diǎn)數(shù) (BigDecimal)、大二進(jìn)制浮點(diǎn)數(shù) (BigFloat) 和運(yùn)算符重載。

?小且易于嵌入:只需幾個(gè) C 文件,無(wú)外部依賴(lài)項(xiàng),一個(gè)簡(jiǎn)單的 hello world 程序的 210 KiB x86 代碼。

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

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

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

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

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

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

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

?帶有 C 庫(kù)包裝器的小型內(nèi)置標(biāo)準(zhǔn)庫(kù)。

3.QuickJS工程簡(jiǎn)介

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      /// 正則表達(dá)式操作符
├── 82.3kB      libregexp.c             /// 正則表達(dá)式相關(guān)
├── 3.26kB      libregexp.h             /// 正則表達(dá)式相關(guān)
├── 3.09kB      list.h                  /// 鏈表實(shí)現(xiàn)
├── 16.7kB      qjs.c                   /// QuickJS stand alone interpreter
├── 22kB        qjsc.c                  /// QuickJS command line compiler
├── 73.1kB      qjscalc.js              /// 數(shù)學(xué)計(jì)算器
├── 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的對(duì)byte-code會(huì)優(yōu)化兩次,通過(guò)一個(gè)簡(jiǎn)單例子看看QuickJS的字節(jié)碼與優(yōu)化器的輸出,以及執(zhí)行過(guò)程。

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

?第一階段(未經(jīng)過(guò)優(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        /// 精簡(jiǎn)成獲取參數(shù)列表中第0個(gè)參數(shù)
        get_arg1 1: b
        add
        return

;; }
sum(1,2);

通過(guò)上述簡(jiǎn)單的函數(shù)調(diào)用,觀察sum函數(shù)調(diào)用過(guò)程中棧幀的變化,通過(guò)計(jì)算可知sum函數(shù)最棧幀大小為兩個(gè)字節(jié)

get_arg0

get_arg1

add

return

1

2

3

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


1



5.內(nèi)存管理

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

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

6.QuickJS簡(jiǎn)單使用

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

sudo make
sudo make install

?qjs: JavaScript代碼解釋器

?qjsc: JavaScript代碼編譯器

?qjscalc: 基于QuickJS的REPL計(jì)算器程序

通過(guò)使用qjs可以直接運(yùn)行一個(gè)JavaScript源碼,通過(guò)qsjc的如下命令,則可以輸出一個(gè)帶有byte-code源碼的可直接運(yùn)行的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;
}

上面的這個(gè)C源文件,通過(guò)如下命令即可編譯成可執(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添加擴(kuò)展

QuickJS只實(shí)現(xiàn)了最基本的JavaScript能力,同時(shí)QuickJS也可以實(shí)現(xiàn)能力的擴(kuò)展,比如給QuickJS添加打開(kāi)文件并讀取文件內(nèi)容的內(nèi)容,這樣在JavaScript代碼中即可通過(guò)js代碼打開(kāi)并讀取到文件內(nèi)容了。

通過(guò)一個(gè)例子來(lái)看看添加擴(kuò)展都需要做哪些操作:

?編寫(xiě)一個(gè)C語(yǔ)言的擴(kuò)展模塊

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

/// js中對(duì)應(yīng)plus函數(shù)的C語(yǔ)言函數(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文件中注冊(cè)模塊

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

?編寫(xiě)一個(gè)my_module.js測(cè)試文件

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í)行文件,通過(guò)執(zhí)行my_module輸出:

my_module.plus: 3

8.使用C API

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

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

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

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

這樣的操作只適合用于測(cè)試一下功能,實(shí)際生產(chǎn)中使用需要一個(gè)即可以在必要的時(shí)候調(diào)用loop又可以做到不搶占過(guò)多的CPU或者只搶占較少的CPU時(shí)間片。

四、libuv

1.libuv簡(jiǎn)價(jià)

libuv 是一個(gè)使用C語(yǔ)言編寫(xiě)的多平臺(tái)支持庫(kù),專(zhuān)注于異步 I/O。 它主要是為 Node.js 使用而開(kāi)發(fā)的,但 Luvit、Julia、uvloop 等也使用它。

功能亮點(diǎn)

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

?異步 TCP 和 UDP 套接字

?異步 DNS 解析

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

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

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

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

?子進(jìn)程

?線(xiàn)程池

?信號(hào)處理

?高分辨率時(shí)鐘

?線(xiàn)程和同步原語(yǔ)

2.libuv運(yùn)行原理

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.簡(jiǎn)單使用

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(`開(kāi)始執(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é)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2023-10-31 18:32:26

WebRTC存儲(chǔ)

2021-05-27 05:22:28

前端引擎平臺(tái)

2022-08-06 08:34:04

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

2021-08-26 05:27:57

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

2023-12-13 13:15:13

平臺(tái)開(kāi)發(fā)實(shí)踐

2009-06-09 21:59:13

語(yǔ)法高亮Javascript

2024-04-30 09:53:12

axios架構(gòu)適配器

2024-05-15 18:59:01

JavaScript語(yǔ)言原型

2022-02-24 18:51:04

跨端框架方案

2019-11-26 09:42:36

代碼開(kāi)發(fā)API

2024-09-23 19:53:27

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

2023-07-03 07:42:42

2024-01-08 08:23:08

OpenCV機(jī)器學(xué)習(xí)計(jì)算機(jī)視覺(jué)

2022-04-15 14:31:02

鴻蒙操作系統(tǒng)

2020-10-09 09:21:45

鴻蒙

2023-07-26 11:22:44

騰訊趙裕

2022-11-30 15:15:48

2022-09-12 07:17:20

redis命令redissynce

2020-08-13 15:36:14

移動(dòng)端跨平臺(tái)小程序
點(diǎn)贊
收藏

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