Skip to content

Instantly share code, notes, and snippets.

@chad3814
Created June 19, 2018 00:54
Show Gist options
  • Save chad3814/50d75d4f13054dc47de8c897f303580e to your computer and use it in GitHub Desktop.
Save chad3814/50d75d4f13054dc47de8c897f303580e to your computer and use it in GitHub Desktop.
async worker/emitter example
{
"targets": [
{
"target_name": "AsyncEmitter",
"sources": [ "emitter.cc" ],
"include_dirs": [],
"dependencies": [],
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"libraries": [],
"xcode_settings": {
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
"CLANG_CXX_LIBRARY": "libc++",
"MACOSX_DEPLOYMENT_TARGET": "10.7",
},
"msvs_settings": {
"VCCLCompilerTool": { "ExceptionHandling": 1 },
},
},
],
}
#include <node.h>
#include <uv.h>
#include <unistd.h>
#include <stdlib.h>
namespace asyncAddon {
using v8::Persistent;
using v8::Function;
using v8::Isolate;
using v8::Local;
using v8::Value;
using v8::Number;
using v8::FunctionCallbackInfo;
using v8::Object;
/**
* Work structure is be used to pass the callback function and data
* from the initiating function to the function which triggers the callback.
*/
struct Work {
uv_work_t request;
uv_async_t async;
Persistent<Function> callback;
int seconds;
};
static void emit(uv_async_t *async) {
Isolate * isolate = Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
Work *work = static_cast<Work *>(async->data);
Local<Value> argv[1] = {Number::New(isolate, work->seconds)};
Local<Function> callback = Local<Function>::New(isolate, work->callback);
callback->Call(isolate->GetCurrentContext()->Global(), 1, argv);
}
/**
* WorkAsync function is the "middle" function which does the work.
* After the WorkAsync function is called, the WorkAsyncComplete function
* is called.
*/
static void WorkAsync(uv_work_t *req) {
Work *work = static_cast<Work *>(req->data);
for (int i = 0; i < 5; i++) {
work->seconds = (rand() %5) + 1;
sleep(work->seconds);
// this signals the emit func, but on the main thread
uv_async_send(&work->async);
}
}
/**
* WorkAsyncComplete function is called once we are ready to trigger the callback
* function in JS.
*/
static void WorkAsyncComplete(uv_work_t *req, int)
{
Isolate * isolate = Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
Work *work = static_cast<Work *>(req->data);
//printf("status %d\n",status);
Local<Value> *argv = NULL;
Local<Function> callback = Local<Function>::New(isolate, work->callback);
callback->Call(isolate->GetCurrentContext()->Global(), 0, argv);
work->callback.Reset();
uv_close((uv_handle_t *)&work->async, NULL);
delete work;
}
/**
* DoTaskAsync is the initial function called from JS. This function returns
* immediately, however starts a uv task which later calls the callback function
*/
void DoTaskAsync(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Work * work = new Work();
work->request.data = work;
work->async.data = work;
// args[0] is where we pick the callback function out of the JS function params.
// Because we chose args[0], we must supply the callback fn as the first parameter
Local<Function> callback = Local<Function>::Cast(args[0]);
work->callback.Reset(isolate, callback);
uv_async_init(uv_default_loop(), &work->async, emit);
uv_queue_work(uv_default_loop(), &work->request, WorkAsync, WorkAsyncComplete);
args.GetReturnValue().Set(Undefined(isolate));
}
/**
* init function declares what we will make visible to node
*/
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "runWorker", DoTaskAsync);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, init)
}
'use strict';
const {runWorker} = require('bindings')('AsyncEmitter');
let interval;
const emit = function (seconds) {
if (seconds === undefined) {
console.log('async is done');
clearInterval(interval);
return;
}
console.log('async slept for', seconds, 'seconds');
};
runWorker(emit);
interval = setInterval(() => console.log('second'), 1000);
{
"name": "async-emitter",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"bindings": "^1.3.0"
},
"scripts": {
"build": "node-gyp configure build --silent",
"clean": "node-gyp clean --silent"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment