Skip to content
This repository was archived by the owner on Feb 17, 2019. It is now read-only.

Commit b6f3e8b

Browse files
NickNasomhdawson
authored andcommitted
Add additional examples
Porting asynchronous example from NAN repo. The original example is hosted here: https://github.com/nodejs/nan/tree/master/examples/async_pi_estimate. Rewrite all the logic using **node-addon-api** See the following issue https://github.com/nodejs/abi-stable-node-addon-examples/issues/10 Added examples for event emitter See: nodejs/node-addon-api#110
1 parent 09885f5 commit b6f3e8b

32 files changed

+690
-0
lines changed

async_pi_estimate/nan/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
In this directory run `node-gyp rebuild` and then `node ./addon.js`

async_pi_estimate/nan/addon.cc

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <nan.h>
2+
#include "sync.h" // NOLINT(build/include)
3+
#include "async.h" // NOLINT(build/include)
4+
5+
using v8::FunctionTemplate;
6+
using v8::Handle;
7+
using v8::Object;
8+
using v8::String;
9+
using Nan::GetFunction;
10+
using Nan::New;
11+
using Nan::Set;
12+
13+
// Expose synchronous and asynchronous access to our
14+
// Estimate() function
15+
NAN_MODULE_INIT(InitAll) {
16+
Set(target, New<String>("calculateSync").ToLocalChecked(),
17+
GetFunction(New<FunctionTemplate>(CalculateSync)).ToLocalChecked());
18+
19+
Set(target, New<String>("calculateAsync").ToLocalChecked(),
20+
GetFunction(New<FunctionTemplate>(CalculateAsync)).ToLocalChecked());
21+
}
22+
23+
NODE_MODULE(addon, InitAll)

async_pi_estimate/nan/addon.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
var addon = require('./build/Release/addon');
2+
var calculations = process.argv[2] || 100000000;
3+
4+
function printResult(type, pi, ms) {
5+
console.log(type, 'method:');
6+
console.log('\tπ ≈ ' + pi +
7+
' (' + Math.abs(pi - Math.PI) + ' away from actual)');
8+
console.log('\tTook ' + ms + 'ms');
9+
console.log();
10+
}
11+
12+
function runSync() {
13+
var start = Date.now();
14+
// Estimate() will execute in the current thread,
15+
// the next line won't return until it is finished
16+
var result = addon.calculateSync(calculations);
17+
printResult('Sync', result, Date.now() - start);
18+
}
19+
20+
function runAsync() {
21+
// how many batches should we split the work in to?
22+
var batches = process.argv[3] || 16;
23+
var ended = 0;
24+
var total = 0;
25+
var start = Date.now();
26+
27+
function done (err, result) {
28+
total += result;
29+
30+
// have all the batches finished executing?
31+
if (++ended === batches) {
32+
printResult('Async', total / batches, Date.now() - start);
33+
}
34+
}
35+
36+
// for each batch of work, request an async Estimate() for
37+
// a portion of the total number of calculations
38+
for (var i = 0; i < batches; i++) {
39+
addon.calculateAsync(calculations / batches, done);
40+
}
41+
}
42+
43+
runSync();
44+
runAsync();

async_pi_estimate/nan/async.cc

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <nan.h>
2+
#include "pi_est.h" // NOLINT(build/include)
3+
#include "async.h" // NOLINT(build/include)
4+
5+
using v8::Function;
6+
using v8::Local;
7+
using v8::Number;
8+
using v8::Value;
9+
using Nan::AsyncQueueWorker;
10+
using Nan::AsyncWorker;
11+
using Nan::Callback;
12+
using Nan::HandleScope;
13+
using Nan::New;
14+
using Nan::Null;
15+
using Nan::To;
16+
17+
class PiWorker : public AsyncWorker {
18+
public:
19+
PiWorker(Callback *callback, int points)
20+
: AsyncWorker(callback), points(points), estimate(0) {}
21+
~PiWorker() {}
22+
23+
// Executed inside the worker-thread.
24+
// It is not safe to access V8, or V8 data structures
25+
// here, so everything we need for input and output
26+
// should go on `this`.
27+
void Execute () {
28+
estimate = Estimate(points);
29+
}
30+
31+
// Executed when the async work is complete
32+
// this function will be run inside the main event loop
33+
// so it is safe to use V8 again
34+
void HandleOKCallback () {
35+
HandleScope scope;
36+
37+
Local<Value> argv[] = {
38+
Null()
39+
, New<Number>(estimate)
40+
};
41+
42+
callback->Call(2, argv, async_resource);
43+
}
44+
45+
private:
46+
int points;
47+
double estimate;
48+
};
49+
50+
// Asynchronous access to the `Estimate()` function
51+
NAN_METHOD(CalculateAsync) {
52+
int points = To<int>(info[0]).FromJust();
53+
Callback *callback = new Callback(To<Function>(info[1]).ToLocalChecked());
54+
55+
AsyncQueueWorker(new PiWorker(callback, points));
56+
}

async_pi_estimate/nan/async.h

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_
2+
#define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_
3+
4+
#include <nan.h>
5+
6+
NAN_METHOD(CalculateAsync);
7+
8+
#endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_

async_pi_estimate/nan/binding.gyp

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "addon",
5+
"sources": [
6+
"addon.cc",
7+
"pi_est.cc",
8+
"sync.cc",
9+
"async.cc"
10+
],
11+
"include_dirs": ["<!(node -e \"require('nan')\")"]
12+
}
13+
]
14+
}

async_pi_estimate/nan/package.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "async_work",
3+
"version": "0.0.0",
4+
"description": "Node.js Addons Example #9",
5+
"main": "addon.js",
6+
"private": true,
7+
"gypfile": true,
8+
"dependencies": {
9+
"nan": "*"
10+
}
11+
}

async_pi_estimate/nan/pi_est.cc

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <cstdlib>
2+
#include "pi_est.h" // NOLINT(build/include)
3+
4+
/*
5+
Estimate the value of π by using a Monte Carlo method.
6+
Take `points` samples of random x and y values on a
7+
[0,1][0,1] plane. Calculating the length of the diagonal
8+
tells us whether the point lies inside, or outside a
9+
quarter circle running from 0,1 to 1,0. The ratio of the
10+
number of points inside to outside gives us an
11+
approximation of π/4.
12+
13+
See https://en.wikipedia.org/wiki/File:Pi_30K.gif
14+
for a visualization of how this works.
15+
*/
16+
17+
inline int randall(unsigned int *p_seed) {
18+
// windows has thread safe rand()
19+
#ifdef _WIN32
20+
return rand(); // NOLINT(runtime/threadsafe_fn)
21+
#else
22+
return rand_r(p_seed);
23+
#endif
24+
}
25+
26+
double Estimate (int points) {
27+
int i = points;
28+
int inside = 0;
29+
unsigned int randseed = 1;
30+
31+
#ifdef _WIN32
32+
srand(randseed);
33+
#endif
34+
35+
// unique seed for each run, for threaded use
36+
unsigned int seed = randall(&randseed);
37+
38+
#ifdef _WIN32
39+
srand(seed);
40+
#endif
41+
42+
while (i-- > 0) {
43+
double x = randall(&seed) / static_cast<double>(RAND_MAX);
44+
double y = randall(&seed) / static_cast<double>(RAND_MAX);
45+
46+
// x & y and now values between 0 and 1
47+
// now do a pythagorean diagonal calculation
48+
// `1` represents our 1/4 circle
49+
if ((x * x) + (y * y) <= 1)
50+
inside++;
51+
}
52+
53+
// calculate ratio and multiply by 4 for π
54+
return (inside / static_cast<double>(points)) * 4;
55+
}

async_pi_estimate/nan/pi_est.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_
2+
#define EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_
3+
4+
double Estimate(int points);
5+
6+
#endif // EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_

async_pi_estimate/nan/sync.cc

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <nan.h>
2+
#include "pi_est.h" // NOLINT(build/include)
3+
#include "sync.h" // NOLINT(build/include)
4+
5+
// Simple synchronous access to the `Estimate()` function
6+
NAN_METHOD(CalculateSync) {
7+
// expect a number as the first argument
8+
int points = info[0]->Uint32Value();
9+
double est = Estimate(points);
10+
11+
info.GetReturnValue().Set(est);
12+
}

async_pi_estimate/nan/sync.h

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_
2+
#define EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_
3+
4+
#include <nan.h>
5+
6+
NAN_METHOD(CalculateSync);
7+
8+
#endif // EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
In this directory run `node-gyp rebuild` and then `node ./addon.js`
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <napi.h>
2+
#include "sync.h" // NOLINT(build/include)
3+
#include "async.h" // NOLINT(build/include)
4+
5+
// Expose synchronous and asynchronous access to our
6+
// Estimate() function
7+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
8+
exports.Set(Napi::String::New(env, "calculateSync"), Napi::Function::New(env, CalculateSync));
9+
exports.Set(Napi::String::New(env, "calculateAsync"), Napi::Function::New(env, CalculateAsync));
10+
return exports;
11+
}
12+
13+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
var addon = require('bindings')('addon');
2+
var calculations = process.argv[2] || 100000000;
3+
4+
function printResult(type, pi, ms) {
5+
console.log(type, 'method:');
6+
console.log('\tπ ≈ ' + pi +
7+
' (' + Math.abs(pi - Math.PI) + ' away from actual)');
8+
console.log('\tTook ' + ms + 'ms');
9+
console.log();
10+
}
11+
12+
function runSync() {
13+
var start = Date.now();
14+
// Estimate() will execute in the current thread,
15+
// the next line won't return until it is finished
16+
var result = addon.calculateSync(calculations);
17+
printResult('Sync', result, Date.now() - start);
18+
}
19+
20+
function runAsync() {
21+
// how many batches should we split the work in to?
22+
var batches = process.argv[3] || 16;
23+
var ended = 0;
24+
var total = 0;
25+
var start = Date.now();
26+
27+
function done (err, result) {
28+
total += result;
29+
30+
// have all the batches finished executing?
31+
if (++ended === batches) {
32+
printResult('Async', total / batches, Date.now() - start);
33+
}
34+
}
35+
36+
// for each batch of work, request an async Estimate() for
37+
// a portion of the total number of calculations
38+
for (var i = 0; i < batches; i++) {
39+
addon.calculateAsync(calculations / batches, done);
40+
}
41+
}
42+
43+
runSync();
44+
runAsync();
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <napi.h>
2+
#include "pi_est.h" // NOLINT(build/include)
3+
#include "async.h" // NOLINT(build/include)
4+
5+
class PiWorker : public Napi::AsyncWorker {
6+
public:
7+
PiWorker(Napi::Function& callback, int points)
8+
: Napi::AsyncWorker(callback), points(points), estimate(0) {}
9+
~PiWorker() {}
10+
11+
// Executed inside the worker-thread.
12+
// It is not safe to access JS engine data structure
13+
// here, so everything we need for input and output
14+
// should go on `this`.
15+
void Execute () {
16+
estimate = Estimate(points);
17+
}
18+
19+
// Executed when the async work is complete
20+
// this function will be run inside the main event loop
21+
// so it is safe to use JS engine data again
22+
void OnOK() {
23+
Napi::HandleScope scope(Env());
24+
Callback().Call({Env().Undefined(), Napi::Number::New(Env(), estimate)});
25+
}
26+
27+
private:
28+
int points;
29+
double estimate;
30+
};
31+
32+
// Asynchronous access to the `Estimate()` function
33+
Napi::Value CalculateAsync(const Napi::CallbackInfo& info) {
34+
int points = info[0].As<Napi::Number>().Uint32Value();
35+
Napi::Function callback = info[1].As<Napi::Function>();
36+
PiWorker* piWorker = new PiWorker(callback, points);
37+
piWorker->Queue();
38+
return info.Env().Undefined();
39+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_
2+
#define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_
3+
4+
#include <napi.h>
5+
6+
Napi::Value CalculateAsync(const Napi::CallbackInfo& info);
7+
8+
#endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "addon",
5+
"sources": [
6+
"addon.cc",
7+
"pi_est.cc",
8+
"sync.cc",
9+
"async.cc"
10+
],
11+
'cflags!': [ '-fno-exceptions' ],
12+
'cflags_cc!': [ '-fno-exceptions' ],
13+
'include_dirs': ["<!@(node -p \"require('node-addon-api').include\")"],
14+
'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"],
15+
'conditions': [
16+
['OS=="win"', {
17+
"msvs_settings": {
18+
"VCCLCompilerTool": {
19+
"ExceptionHandling": 1
20+
}
21+
}
22+
}],
23+
['OS=="mac"', {
24+
"xcode_settings": {
25+
"CLANG_CXX_LIBRARY": "libc++",
26+
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
27+
'MACOSX_DEPLOYMENT_TARGET': '10.7'
28+
}
29+
}]
30+
]
31+
}
32+
]
33+
}

0 commit comments

Comments
 (0)