使用NAPI扩展TS接口时,常用属性和实现接口的基本用法?

使用NAPI扩展TS接口时,常用属性和实现接口的基本用法

阅读 489
avatarAI BotBETA

当你使用 Node.js 的 N-API (Node-API) 来扩展 TypeScript 接口时,你可以使用以下常用属性和实现接口的基本用法:

常用属性

  1. napi_env:
* 这是一个指向 N-API 环境的指针,所有 N-API 函数都需要这个环境指针作为第一个参数。
* 你可以通过 `napi_create_function`、`napi_create_object` 等函数获取它。
  1. napi_value:
* 表示一个 JavaScript 值。
* 你可以使用它来传递和接收 JavaScript 值。
  1. napi_callback_info:
* 当调用异步回调函数时,这个结构体包含了回调的上下文信息。

实现接口的基本用法

  1. 初始化 N-API:

使用 napi_init 函数初始化 N-API 环境。

napi_env env;
napi_status status = napi_init(node_env, &env);
  1. 创建对象:

使用 napi_create_object 函数创建一个新的 JavaScript 对象。

napi_value obj;
status = napi_create_object(env, &obj);
  1. 定义属性:

使用 napi_set_named_property 函数为对象设置属性。

napi_value propName, propValue;
// ... 初始化 propName 和 propValue ...
status = napi_set_named_property(env, obj, propName, propValue);
  1. 定义方法:

使用 napi_create_function 函数为对象创建方法。

napi_value method;
napi_value methodName, methodCallback;
// ... 初始化 methodName 和 methodCallback ...
status = napi_create_function(env, NULL, 0, methodCallback, NULL, &method);
status = napi_set_named_property(env, obj, methodName, method);
  1. 导出模块:

使用 napi_create_modulenapi_set_module_exports 函数导出你的模块。

napi_value exports;
status = napi_create_module(env, NULL, &exports);
status = napi_set_module_exports(env, exports, obj);
  1. 注册模块:

在你的 node_modules 目录下创建一个 JavaScript 文件(例如 addon.js),然后使用 require 函数导入你的 C/C++ 扩展。

const addon = require('./build/Release/addon');
module.exports = addon;

注意:上述代码仅为示例,实际使用时可能需要根据你的具体需求进行调整。

此外,N-API 还提供了许多其他函数和属性,你可以参考 Node.js 的官方文档以获取更详细的信息。

1 个回答
  1. env是使用napi的模块化编程,注册模块之后,调用回调的时候会通过回调函数调用过来:
static napi_value CallNapi(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value object = nullptr; 
    napi_status status; 
    status = napi_get_cb_info(env, info, &argc, &object, nullptr, nullptr); 
    return object; 
} 
NAPI_MODULE_INIT() { 
    napi_property_descriptor desc[] = { 
        { "callNapi", nullptr, CallNapi, nullptr, nullptr, nullptr, napi_default, nullptr } 
    }; 
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 
    return exports; 
}
  1. callback实现:
#include "napi/native_api.h" 
#include <assert.h> 
static napi_value NativeCall(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = { nullptr }; 
    napi_status status; 
    status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 
    assert(status == napi_ok); 
    napi_valuetype valuetype; 
    napi_typeof(env, args[0], &valuetype); 
    if (valuetype != napi_valuetype::napi_function) { 
        napi_throw_type_error(env, nullptr, "napi_function is expected"); 
    } 
    napi_value cb = args[0]; 
    napi_value undefined; 
    status = napi_get_undefined(env, &undefined); 
    assert(status == napi_ok); 
    napi_value argv[2] = { nullptr }; 
    status = napi_create_int32(env, 1, &argv[0]); 
    assert(status == napi_ok); 
    status = napi_create_int32(env, 2, &argv[1]); 
    assert(status == napi_ok); 
    napi_value result; 
    status = napi_call_function(env, undefined, cb, 2, argv, &result); 
    assert(status == napi_ok); 
    return nullptr; 
} 
EXTERN_C_START 
static napi_value Init(napi_env env, napi_value exports) { 
    napi_property_descriptor desc[] = { 
        { "nativeCall", nullptr, NativeCall, nullptr, nullptr, nullptr, napi_default, nullptr } 
    }; 
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 
    return exports; 
} 
EXTERN_C_END 
static napi_module module = { 
    .nm_version = 1, 
    .nm_flags = 0, 
    .nm_filename = nullptr, 
    .nm_register_func = Init, 
    .nm_modname = "callback", 
    .nm_priv = nullptr, 
    .reserved = { 0 }, 
}; 
extern "C" __attribute__((constructor)) void RegisterCallbackModule(void) { 
    napi_module_register(&module); 
}
  1. Promise实现参考:
#include "napi/native_api.h" 
// Empty value so that macros here are able to return NULL or void 
#define NAPI_RETVAL_NOTHING  // Intentionally blank 
#define GET_AND_THROW_LAST_ERROR(env)                                                                    
    do {                                                                                               
        const napi_extended_error_info* errorInfo = nullptr;                                             
        napi_get_last_error_info((env), &errorInfo);                                                     
        bool isPending = false;                                                                          
        napi_is_exception_pending((env), &isPending);                                                    
        if (!isPending && errorInfo != nullptr) {                                                        
            const char* errorMessage =                                                                   
                errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message";  
            napi_throw_error((env), nullptr, errorMessage);                                              
        }                                                                                                
    } while (0) 
#define NAPI_ASSERT_BASE(env, assertion, message, retVal)                                     
    do {                                                                                      
        if (!(assertion)) {                                                                   
            napi_throw_error((env), nullptr, "assertion ("#assertion") failed:" message);  
            return retVal;                                                                    
        }                                                                                     
    } while (0) 
#define NAPI_ASSERT(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, nullptr) 
#define NAPI_ASSERT_RETURN_VOID(env, assertion, message)  
        NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING) 
#define NAPI_CALL_BASE(env, theCall, retVal)  
    do {                                      
        if ((theCall) != napi_ok) {           
            GET_AND_THROW_LAST_ERROR((env));  
            return retVal;                    
        }                                     
    } while (0) 
#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) 
#define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING) 
struct AsyncData { 
    napi_deferred deferred; 
    napi_async_work work; 
    int32_t arg; 
    double retVal; 
}; 
double DoSomething(int32_t val) { 
    if (val != 0) { 
        return 1.0 / val;  
    } 
    return 0; 
} 
void ExecuteCallback(napi_env env, void* data) { 
    AsyncData* asyncData = reinterpret_cast<AsyncData*>(data); 
    asyncData->retVal = DoSomething(asyncData->arg); 
} 
void CompleteCallback(napi_env env, napi_status status, void* data) { 
    AsyncData* asyncData = reinterpret_cast<AsyncData*>(data); 
    napi_value retVal; 
    if (asyncData->retVal == 0) { 
        NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, "arg can't be zero", NAPI_AUTO_LENGTH, &retVal)); 
        NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncData->deferred, retVal)); 
    } else { 
        NAPI_CALL_RETURN_VOID(env, napi_create_double(env, asyncData->retVal, &retVal)); 
        NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncData->deferred, retVal)); 
    } 
    NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, asyncData->work)); 
    asyncData->work = nullptr; 
    asyncData->deferred = nullptr; 
    delete asyncData; 
} 
static napi_value NativeCall(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = { nullptr }; 
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); 
    int32_t arg; 
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &arg)); 
    // Create promise 
    napi_deferred deferred; 
    napi_value promise; 
    NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); 
    AsyncData* data = new AsyncData; 
    data->deferred = deferred; 
    data->arg = arg; 
    napi_async_work work; 
    napi_value workName; 
    napi_create_string_utf8(env, "promise", NAPI_AUTO_LENGTH, &workName); 
    NAPI_CALL(env, napi_create_async_work(env, nullptr, workName,ExecuteCallback, CompleteCallback, data, &work)); 
    data->work = work; 
    NAPI_CALL(env, napi_queue_async_work(env, work)); 
    return promise; 
} 
EXTERN_C_START 
static napi_value Init(napi_env env, napi_value exports) { 
    napi_property_descriptor desc[] = { 
        { "nativeCall", nullptr, NativeCall, nullptr, nullptr, nullptr, napi_default, nullptr } 
    }; 
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 
    return exports; 
} 
EXTERN_C_END 
static napi_module demoModule = { 
    .nm_version = 1, 
    .nm_flags = 0, 
    .nm_filename = nullptr, 
    .nm_register_func = Init, 
    .nm_modname = "promise", 
    .nm_priv = nullptr, 
    .reserved = { 0 }, 
}; 
extern "C" __attribute__((constructor)) void RegisterPromiseModule(void) { 
    napi_module_register(&demoModule); 
}
  1. libuv使用:可以直接导入libuv三方库使用。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进