Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
API tuning: two minor changes for usability. (#29)
Browse files Browse the repository at this point in the history
1. Make broadcast/execute args optional.
2. Introduce 'global.napa' to access napajs module.
  • Loading branch information
daiyip authored Aug 8, 2017
1 parent cb919f3 commit 6b4e183
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 61 deletions.
1 change: 1 addition & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# API References

## Core modules
- Napa.js specific [`global`](./napa-globals.md) variables
- Namespace [`zone`](./zone.md): Multi-thread JavaScript runtime
- Namespace [`transport`](./transport.md): Passing JavaScript values across threads
- Namespace [`store`](./store.md): Sharing JavaScript values across threads
Expand Down
20 changes: 20 additions & 0 deletions docs/api/napa-globals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Napa.js specific global variables

This file describes Napa.js specific globals, please refer to [this documentation](./node-api.md#globals) for Node.js globals.

## `global.napa`
Shortcut to access `napajs` module in all Napa enabled isolates. This is helpful to avoid extra `require` when using `napajs` module in anonymous function during `broadcast` or `execute`.

Example:
```js
var napa = require('napajs');

var zone = napa.zone.create('zone1');

function test() {
global.napa.log('hi');
}

zone.execute(test);

```
12 changes: 6 additions & 6 deletions docs/api/zone.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
- Interface [`Zone`](#zone)
- [`zone.id: string`](#zone-id)
- [`zone.broadcast(code: string): Promise<void>`](#broadcast-code)
- [`zone.broadcast(function: (...args: any[]) => void, args: any[]): Promise<void>`](#broadcast-function)
- [`zone.execute(moduleName: string, functionName: string, args: any[], options?: CallOptions): Promise<Result>`](#execute-by-name)
- [`zone.execute(function: (...args[]) => any, args: any[], options?: CallOptions): Promise<Result>`](#execute-anonymous-function)
- [`zone.broadcast(function: (...args: any[]) => void, args?: any[]): Promise<void>`](#broadcast-function)
- [`zone.execute(moduleName: string, functionName: string, args?: any[], options?: CallOptions): Promise<Result>`](#execute-by-name)
- [`zone.execute(function: (...args[]) => any, args?: any[], options?: CallOptions): Promise<Result>`](#execute-anonymous-function)
- Interface [`CallOptions`](#call-options)
- [`options.timeout: number`](#call-options-timeout)
- Interface [`Result`](#result)
Expand Down Expand Up @@ -119,7 +119,7 @@ zone.broadcast('var state = 0;')
console.log('broadcast failed.')
});
```
### <a name="broadcast-function"></a> zone.broadcast(function: (...args: any[]) => void, args: any[]): Promise\<void\>
### <a name="broadcast-function"></a> zone.broadcast(function: (...args: any[]) => void, args?: any[]): Promise\<void\>
It asynchronously broadcasts an anonymous function with its arguments to all workers, which returns a Promise of void. If any of the workers failed to execute the code, promise will be rejected with an error message.

*Please note that Napa doesn't support closure in 'function' during broadcast.
Expand All @@ -137,7 +137,7 @@ zone.broadcast((state) => {
console.log('broadcast failed:', error)
});
```
### <a name="execute-by-name"></a> zone.execute(moduleName: string, functionName: string, args: any[], options?: CallOptions): Promise\<any\>
### <a name="execute-by-name"></a> zone.execute(moduleName: string, functionName: string, args?: any[], options?: CallOptions): Promise\<any\>
Execute a function asynchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`Result`](#result). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.

Example: Execute function 'bar' in module 'foo', with arguments [1, 'hello', { field1: 1 }]. 300ms timeout is applied.
Expand All @@ -156,7 +156,7 @@ zone.execute(

```

### <a name="execute-anonymous-function"></a> zone.execute(function: (...args: any[]) => any, args: any[], options?: CallOptions): Promise\<any\>
### <a name="execute-anonymous-function"></a> zone.execute(function: (...args: any[]) => any, args?: any[], options?: CallOptions): Promise\<any\>

Execute an anonymous function asynchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns a Promise of [`Result`](#result). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.

Expand Down
5 changes: 4 additions & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ export { log, memory, metric, runtime, store, transport, zone };

// Add execute proxy to global context.
import { call } from './zone/function-call';
(<any>(global))["__napa_zone_call__"] = call;
(<any>(global))["__napa_zone_call__"] = call;

// Export 'napa' in global for all isolates that require napajs.
(<any>(global))["napa"] = exports;
10 changes: 7 additions & 3 deletions lib/zone/zone-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface FunctionSpec {
transportContext: transport.TransportContext;
}

class ExecuteResult implements zone.Result{
class Result implements zone.Result{

constructor(payload: string, transportContext: transport.TransportContext) {
this._payload = payload;
Expand Down Expand Up @@ -70,13 +70,13 @@ export class ZoneImpl implements zone.Zone {
});
}

public execute(arg1: any, arg2: any, arg3?: any, arg4?: any) : Promise<zone.Result> {
public execute(arg1: any, arg2?: any, arg3?: any, arg4?: any) : Promise<zone.Result> {
let spec : FunctionSpec = this.createExecuteRequest(arg1, arg2, arg3, arg4);

return new Promise<zone.Result>((resolve, reject) => {
this._nativeZone.execute(spec, (result: any) => {
if (result.code === 0) {
resolve(new ExecuteResult(
resolve(new Result(
result.returnValue,
transport.createTransportContext(true, result.contextHandle)));
} else {
Expand Down Expand Up @@ -136,6 +136,10 @@ export class ZoneImpl implements zone.Zone {
options = arg4;
}

if (args == null) {
args = [];
}

// Create a non-owning transport context which will be passed to execute call.
let transportContext: transport.TransportContext = transport.createTransportContext(false);
return {
Expand Down
6 changes: 3 additions & 3 deletions lib/zone/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,21 @@ export interface Zone {
/// <param name="func"> The JS function. </param>
/// <param name="args"> The arguments that will pass to the function. </param>
/// <returns> A promise which is resolved when broadcast completes and rejected when failed. </returns>
broadcast(func: (...args: any[]) => void, args: any[]) : Promise<void>;
broadcast(func: (...args: any[]) => void, args?: any[]) : Promise<void>;

/// <summary> Executes the function on one of the zone workers. </summary>
/// <param name="module"> The module name that contains the function to execute. </param>
/// <param name="func"> The function name to execute. </param>
/// <param name="args"> The arguments that will pass to the function. </param>
/// <param name="options"> Call options, defaults to DEFAULT_CALL_OPTIONS. </param>
/// <returns> A promise of result which is resolved when execute completes, and rejected when failed. </returns>
execute(module: string, func: string, args: any[], options?: CallOptions) : Promise<Result>;
execute(module: string, func: string, args?: any[], options?: CallOptions) : Promise<Result>;

/// <summary> Executes the function on one of the zone workers. </summary>
/// <param name="func"> The JS function to execute. </param>
/// <param name="args"> The arguments that will pass to the function. </param>
/// <param name="options"> Call options, defaults to DEFAULT_CALL_OPTIONS. </param>
/// <returns> A promise of result which is resolved when execute completes, and rejected when failed. </returns>
execute(func: (...args: any[]) => any, args: any[], options?: CallOptions) : Promise<Result>;
execute(func: (...args: any[]) => any, args?: any[], options?: CallOptions) : Promise<Result>;
}

6 changes: 3 additions & 3 deletions test/memory-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('napajs/memory', function() {
});

it('@napa: crtAllocator', () => {
napaZone.execute(NAPA_ZONE_TEST_MODULE, "crtAllocatorTest", []);
napaZone.execute(NAPA_ZONE_TEST_MODULE, "crtAllocatorTest");
});

it('@node: defaultAllocator', () => {
Expand All @@ -45,7 +45,7 @@ describe('napajs/memory', function() {
});

it('@napa: defaultAllocator', () => {
napaZone.execute(NAPA_ZONE_TEST_MODULE, "defaultAllocatorTest", []);
napaZone.execute(NAPA_ZONE_TEST_MODULE, "defaultAllocatorTest");
});

it('@node: debugAllocator', () => {
Expand All @@ -63,7 +63,7 @@ describe('napajs/memory', function() {
});

it('@napa: debugAllocator', () => {
napaZone.execute(NAPA_ZONE_TEST_MODULE, "debugAllocatorTest", []);
napaZone.execute(NAPA_ZONE_TEST_MODULE, "debugAllocatorTest");
});
});
});
36 changes: 18 additions & 18 deletions test/module-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('napajs/module', function () {
describe('resolve', function () {
// TODO: support correct __dirname in anonymous function and move tests from 'resolution-tests.js' here.
it('require.resolve', () => {
return napaZone.execute(__dirname + "/module/resolution-tests.js", "run", []);
return napaZone.execute(__dirname + "/module/resolution-tests.js", "run");
});
});

Expand All @@ -83,15 +83,15 @@ describe('napajs/module', function () {

assert(process.argv.length > 0);
assert(process.argv[0].includes('node'));
}, []);
});
});

it('execPath', () => {
return napaZone.execute(() => {
var assert = require("assert");

assert(process.execPath.includes('node'));
}, []);
});
});

it('env', () => {
Expand All @@ -100,7 +100,7 @@ describe('napajs/module', function () {

process.env.test = "napa-test";
assert.equal(process.env.test, "napa-test");
}, []);
});
});

it('platform', () => {
Expand All @@ -111,7 +111,7 @@ describe('napajs/module', function () {
process.platform == 'darwin' ||
process.platform == 'linux' ||
process.platform == 'freebsd');
}, []);
});
});

it('umask', () => {
Expand All @@ -120,7 +120,7 @@ describe('napajs/module', function () {

var old = process.umask(0);
assert.equal(process.umask(old), 0);
}, []);
});
});

it('chdir', () => {
Expand All @@ -133,7 +133,7 @@ describe('napajs/module', function () {
assert(cwd.includes(process.cwd()));
process.chdir(cwd);
assert.equal(cwd, process.cwd());
}, []);
});
});

it('pid', () => {
Expand All @@ -142,7 +142,7 @@ describe('napajs/module', function () {

assert.notEqual(typeof process.pid, undefined);
assert(!isNaN(process.pid));
}, []);
});
});
});

Expand Down Expand Up @@ -234,7 +234,7 @@ describe('napajs/module', function () {
} else {
assert.equal(path.normalize('a\\b\\..\\c/./d/././.'), "a/c/d");
}
}, []);
});
});

it('resolve', () => {
Expand All @@ -253,7 +253,7 @@ describe('napajs/module', function () {
assert.equal(path.resolve("abc", "efg", "../hij", "./xyz.txt"), process.cwd() + "/abc/hij/xyz.txt");
assert.equal(path.resolve("abc", "/a.txt"), "/a.txt");
}
}, []);
});
});

it('join', () => {
Expand All @@ -266,7 +266,7 @@ describe('napajs/module', function () {
} else {
assert.equal(path.join("/foo", "bar", "baz/asdf", "quux", ".."), "/foo/bar/baz/asdf");
}
}, []);
});
});

// TODO: fix bugs
Expand All @@ -286,7 +286,7 @@ describe('napajs/module', function () {
assert.equal(path.dirname("/etc"), "/");
assert.equal(path.dirname("/etc/passwd"), "/etc");
}
}, []);
});
});

it('basename', () => {
Expand All @@ -305,7 +305,7 @@ describe('napajs/module', function () {
assert.equal(path.basename("/test/abc.txt", ".txt"), "abc");
assert.equal(path.basename("/windows/abc.txt", ".Txt"), "abc.txt");
}
}, []);
});
});

// TODO: fix bugs
Expand All @@ -324,7 +324,7 @@ describe('napajs/module', function () {
assert.equal(path.extname("/test/a.json.txt"), ".txt");
assert.equal(path.extname("/test/a."), ".");
}
}, []);
});
});

it('isAbsolute', () => {
Expand All @@ -345,7 +345,7 @@ describe('napajs/module', function () {
assert.equal(path.isAbsolute("./abc"), false);
assert.equal(path.isAbsolute("abc"), false);
}
}, []);
});
});

it('relative', () => {
Expand All @@ -364,7 +364,7 @@ describe('napajs/module', function () {
assert.equal(path.relative("/test/a", "a.txt"), "../.." + process.cwd() + "/a.txt");
assert.equal(path.relative("/test/a", "/test/"), "..");
}
}, []);
});
});

it('sep', () => {
Expand All @@ -377,7 +377,7 @@ describe('napajs/module', function () {
} else {
assert.equal(path.sep, "/");
}
}, []);
});
});
});

Expand All @@ -388,7 +388,7 @@ describe('napajs/module', function () {
var os = require("os");

assert(os.type() == "Windows_NT" || os.type() == "Darwin" || os.type() == "Linux");
}, []);
});
});
});
});
Expand Down
8 changes: 3 additions & 5 deletions test/napa-zone/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import * as assert from 'assert';
import * as path from "path";
import * as napa from '../../lib/index';
let napaDir: string = path.resolve(__dirname, '../..');

export function bar(input: any) {
return input;
Expand Down Expand Up @@ -95,12 +94,11 @@ export function executeTestFunctionWithTimeout(id: string, waitTimeInMS: number,
export function executeWithTransportableArgs(id: string): Promise<any> {
let zone = napa.zone.get(id);
return new Promise((resolve, reject) => {
zone.execute((allocator: napa.memory.Allocator, napaDir: string) => {
zone.execute((allocator: napa.memory.Allocator) => {
var assert = require("assert");
var napa = require(napaDir);
assert.deepEqual(allocator.handle, napa.memory.crtAllocator.handle);
assert.deepEqual(allocator.handle, (<any>global).napa.memory.crtAllocator.handle);
return 1;
}, [napa.memory.crtAllocator, napaDir])
}, [napa.memory.crtAllocator])
.then ((result: napa.zone.Result) => resolve(result.value))
.catch((error: any) => reject(error));
});
Expand Down
4 changes: 2 additions & 2 deletions test/store-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('napajs/store', function () {
let store2CreationComplete: Promise<napa.zone.Result>;

it('@napa: store.getOrCreate', () => {
store2CreationComplete = napaZone.execute(NAPA_ZONE_TEST_MODULE, "getOrCreateStoreTest", []);
store2CreationComplete = napaZone.execute(NAPA_ZONE_TEST_MODULE, "getOrCreateStoreTest");
});

it('@node: store.get', async () => {
Expand All @@ -46,7 +46,7 @@ describe('napajs/store', function () {
});

it('@napa: store.get', () => {
napaZone.execute(NAPA_ZONE_TEST_MODULE, "getStoreTest", []);
napaZone.execute(NAPA_ZONE_TEST_MODULE, "getStoreTest");
});

it('simple types: set in node, get in node', () => {
Expand Down
Loading

0 comments on commit 6b4e183

Please sign in to comment.