Escritura del complemento Node.js (9): subproceso seguro local para realizar JS Promise

Lo que este artículo implementa es implementar Native Promise en el complemento C/C++, llamar a Native Thread para realizar tareas en segundo plano y volver a la interfaz JS después de realizar tareas en segundo plano. palabra clave.

Principio de implementación de la promesa

Las siguientes encapsulaciones son el núcleo de la implementación de este complemento. No hay documentos específicos, por lo que solo podemos ver el análisis del caso del código fuente.

Napi::Promise::Deferred  //Promise C/C++实现对象
Napi::Promise::Deferred::Resolve() // 相对于js promise的resolve()
Napi::Promise::Deferred::Promise() // 相对于js promise的promise()
Napi::ThreadSafeFunction::New()  //实现一个线程安全的js函数
std::thread //c++11 异步线程的实现

El efecto es el siguiente

Después de que el tiempo se emite de forma asíncrona, la función js finalmente devuelve verdadero, y el código de implementación está en

El código de llamada en el lado js es el siguiente

const { createTSFN } = require('bindings')('addon.node');

//异步执行C/C++插件回调
const callback = (...args) => {
    console.log(new Date, ...args);
};

void async function() { 
    //await等待
    let ret=await createTSFN(callback) ;
    console.log(ret);
}();

El código del complemento C/C++ es el siguiente

#include <chrono>
#include <thread>
#include "napi.h"

constexpr size_t ARRAY_LENGTH = 10;

// 定义线上安全结构上下文
struct TsfnContext {
    TsfnContext(Napi::Env env) : deferred(Napi::Promise::Deferred::New(env)) {
        for (size_t i = 0; i < ARRAY_LENGTH; ++i) ints[i] = i;
    };
    // 本地Promise到js返回
    Napi::Promise::Deferred deferred;
    // 本地线程
    std::thread nativeThread;
    // Some data to pass around
    int ints[ARRAY_LENGTH];
    //线程安全函数
    Napi::ThreadSafeFunction tsfn;
};


void threadEntry(TsfnContext* context) {
    auto callback = [](Napi::Env env, Napi::Function jsCallback, int* data) {
        jsCallback.Call({Napi::Number::New(env, *data)});
    };
    for (size_t index = 0; index < ARRAY_LENGTH; ++index) {
        //执行对JavaScript的调用
        napi_status status =
                context->tsfn.BlockingCall(&context->ints[index], callback);
        if (status != napi_ok) {
            Napi::Error::Fatal(
                    "ThreadEntry",
                    "Napi::ThreadSafeNapi::Function.BlockingCall() failed");
        }
        // 休眠
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
    // 释放线程安全函数
    //创建几个就释放几次
    context->tsfn.Release();
}

//垃圾清理 类似js上下文析构函数
void FinalizerCallback(Napi::Env env,
                       void* finalizeData,
                       TsfnContext* context) {
    //等待本地thread结束
    context->nativeThread.join();
    //await createTSFN()返回 true
    context->deferred.Resolve(Napi::Boolean::New(env, true));
    delete context;
}


// 创建线程安全函数和本地线程
Napi::Value CreateTSFN(const Napi::CallbackInfo& info) {
    //js引擎环境
    Napi::Env env = info.Env();
    // 构造上下文数据
    auto ctxData = new TsfnContext(env);
    // 创建一个线程安全函数
    ctxData->tsfn = Napi::ThreadSafeFunction::New(
            env,                           // Environment
            info[0].As<Napi::Function>(),  // js回调函数
            "TSFN22",                        // 随意名字
            0,                             // 最大队列数
            1,                             // 初始化线程数量
            ctxData,                      // 自定义上下文,
            FinalizerCallback,             // 析构函数
            (void*)nullptr                 // 析构函数 数据
    );
    //创建本地线程
    ctxData->nativeThread = std::thread(threadEntry, ctxData);
    // 函数的终结回调
    return ctxData->deferred.Promise();
}

//createTSFN入口
Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports["createTSFN"] = Napi::Function::New(env, CreateTSFN);
    return exports;
}

NODE_API_MODULE(addon, Init)

Hasta ahora hemos realizado la encapsulación de Native Promise

 

Supongo que te gusta

Origin blog.csdn.net/yue7603835/article/details/122368189
Recomendado
Clasificación