Как создать асинхронную функцию с помощью NAPI, возвращающую обещания
Я пытаюсь создать модуль узла с помощью NAPI . Мне нужно создать асинхронную функцию, которая возвращает обещания. Я не хочу, чтобы эта функция testasyn блокировала цикл событий NodeJS. do_something_asynchronous - это синхронная функция.
napi_deferred do_something_synchronous(napi_env env,napi_deferred deferred){
printf("\n3) Function called");
//napi_deferred deferred;
napi_value undefined;
napi_status status;
// Create a value with which to conclude the deferred.
status = napi_get_undefined(env, &undefined);
if (status != napi_ok) return NULL;
sleep(5);
// Resolve or reject the promise associated with the deferred depending on
// whether the asynchronous action succeeded.
if (false) {
printf("\n5) Success\nXXXXXXX");
status = napi_resolve_deferred(env, deferred, undefined);
} else {
printf("\nReject");
status = napi_reject_deferred(env, deferred, undefined);
}
if (status != napi_ok) return NULL;
// At this point the deferred has been freed, so we should assign NULL to it.
deferred = NULL;
}
//Function will be called from the js
napi_value testasynfunction(napi_env env, napi_callback_info info){
printf("XXXXX Hello \n");
napi_deferred deferred;
napi_value promise;
napi_status status;
// Create the promise.
status = napi_create_promise(env, &deferred, &promise);
if (status != napi_ok) return NULL;
printf("\n1) Calling function to do something");
do_something_synchronous(env,deferred);
//std::async(do_something_asynchronous,env,deferred);
printf("\n2) Returning Promise");
return promise;
}
napi_property_descriptor testasync = DECLARE_NAPI_METHOD("testasyn", testasynfunction);
status = napi_define_properties(env, exports, 1, &testasync);
assert(status == napi_ok);
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
Вопрос: 1) Как я могу запустить do_something_synchronous в асинхронном режиме, чтобы цикл событий nodejs не блокировался и не возвращал обещания?
1 ответ
Следующий фрагмент кода является ключевым компонентом этой асинхронной операции. Функция napi_create_async_work() выделяет рабочий объект, где мы можем указать функцию обработчика рабочего, скажем, в нашем случае ExecuteMyPromise1() (с его помощью можно развернуть длительную или тяжелую задачу процесса). Эта функция будет очередь для рабочего пула потоков и он будет получать асинхронно параллельно с node.js основного потока цикла событий.
Пока все выглядит нормально, проблема возникнет, когда функция ExecuteMyPromise1 планирует обменяться результатом со слоем JavaScript непосредственно из рабочего потока. Любая операция JavaScript обычно может быть вызвана только из основного потока собственного надстройки. Затем для этого обмена результатами мы должны использовать другую встроенную функцию, которая будет вызываться из основного потока. Вот почему мы используем обработчик функции CompleteMyPromise1 (если есть какие-либо окончательные действия по очистке, которые также выполняются с помощью этой функции). Эта собственная функция будет вызываться из потока основного цикла событий, когда асинхронная логика завершена или отменена.
// The function called by javascript to get a promise returned.
napi_value MyPromise1(napi_env env, napi_callback_info info)
{
// -- -- -- --
// -- -- -- --
// Create a promise object.
status = napi_create_promise(env, &promDataEx->deferred, &promise);
if (status != napi_ok)
{
napi_throw_error(env, NULL, "Unable to create promise.");
}
// -- -- -- --
// -- -- -- --
{
// Create the async function.
napi_value resource_name;
napi_create_string_utf8(env, "MyPromise1", -1, &resource_name);
napi_create_async_work(env, NULL, resource_name,
ExecuteMyPromise1, CompleteMyPromise1,
promDataEx, &promDataEx->work);
napi_queue_async_work(env, promDataEx->work);
}
return promise;
}
// Execute the asynchronous work.
void ExecuteMyPromise1(napi_env env, void *data)
{
prom_data_ex_t *promDataEx = (prom_data_ex_t *)data;
// Calculate prime count
promDataEx->PrimeCount = CPrimeCount( promDataEx->x, promDataEx->y );
// Set the status as asynchronous_action is success
promDataEx->asynchronous_action_status = 0;
//sleep(3);
}
// Handle the completion of the asynchronous work.
void CompleteMyPromise1(napi_env env, napi_status status, void *data)
{
napi_value rcValue;
prom_data_ex_t *promDataEx = (prom_data_ex_t *)data;
napi_create_int32(env, promDataEx->PrimeCount, &rcValue);
// Resolve or reject the promise associated with the deferred depending on
// whether the asynchronous action succeeded.
if ( promDataEx->asynchronous_action_status == 0) // Success
{
status = napi_resolve_deferred(env, promDataEx->deferred, rcValue);
}
else
{
napi_value undefined;
status = napi_get_undefined(env, &undefined);
status = napi_reject_deferred(env, promDataEx->deferred, undefined );
}
if (status != napi_ok)
{
napi_throw_error(env, NULL, "Unable to create promise result.");
}
napi_delete_async_work(env, promDataEx->work);
free(promDataEx);
}
Вот полный пример кода для него https://github.com/msatyan/MyNodeC/blob/master/src/mync1/MyPromise1.cpp
Вызов JavaScrip - это TestPromiseWithAsync()https://github.com/msatyan/MyNodeC/blob/master/test/TestExtensions.js