Merged PR 293286: Documentation iteration 2

1. add metric.md and log.md
2. fix anchor issue in VSTS on displaying markdown format.
3. remove some legacy md files.
This commit is contained in:
Daiyi Peng 2017-06-13 00:54:22 +00:00 коммит произвёл Daiyi Peng
Родитель a641034ecc
Коммит f41cb059be
19 изменённых файлов: 488 добавлений и 269 удалений

Просмотреть файл

@ -20,6 +20,12 @@ zone.execute(
console.log(result.value);
});
```
## Features
- Multi-threaded JavaScript runtime
- Node.JS compatible module architecture with NPM support
- API for object transportation, object sharing and synchronization across JavaScript threads
- API for pluggable logging, metric and memory allocator
- Distributed as a Node.JS module, as well as supporting embed scenarios
## Architecture
In Napa.JS, all works related to multi-threading are around the concept of `Zone`,
@ -34,20 +40,10 @@ Workers across different zones are asymmetrical: they may load different code, o
Napa.JS provides API to access current or other zones in JavaScript, thus a parallelizable workflow can be easily described by `zone.execute` across workers or zones. Node.JS event loop is exposed as a single-worker 'virtual' zone. Thus code running in Napa.JS isolates can call to Node.JS world via `zone.node.execute`.
## Features
- Multi-threaded JavaScript execution
- Node.JS compatible module architecture with NPM support
- JavaScript API for synchronization across JavaScript threads
- JavaScript API for object transportation and sharing across JavaScript threads
- C++ API for customizable memory allocation for native objects
- C++ API for pluggable logging and metrics
- C/C++ API for embedders
## Documentation
- [API reference](docs/api/index.md)
- [Benchmarks](benchmark/README.md)
- [Embedder's guide](docs/embedder/index.md)
- [Examples](docs/examples/index.md)
- [Benchmarks](docs/benchmarks/index.md)
- [Design docs](docs/design/index.md)
## Contribute

Просмотреть файл

@ -1,12 +1,16 @@
# API References
## Napa.JS APIs
- [zone](./zone.md): Multi-thread JavaScript runtime
- [transport](./transport.md): Transporting objects between JavaScript threads
- [memory](./memory.md): Handling native objects and memories.
- [sync](./sync.md): Synchronization between JavaScript threads
## Core modules
- namespace [`zone`](./zone.md): Multi-thread JavaScript runtime
- namespace [`transport`](./transport.md): Passing objects across JavaScript threads
- namespace [`store`](./store.md): Sharing objects across JavaScript threads
- namespace [`sync`](./sync.md): Synchronization across JavaScript threads
- namespace [`memory`](./memory.md): Handling native objects and memories
- namespace [`metric`](./metric.md): API for pluggable metrics.
- function [`log`](./log.md): API for pluggable logging.
- [module](./module.md): Writing Napa.JS modules
## Node.JS compatibility
- [List of supported Node APIs](./node-api.md)
## Supported Node.JS APIs
- [List of supported Node APIs](./node.md)
## API for module developers
- [Writing Napa.JS modules](./module.md):

98
docs/api/log.md Normal file
Просмотреть файл

@ -0,0 +1,98 @@
# function `log`
## Table of Contents
- [Logging basics](#logging-basics)
- [C++ API](#c-api)
- [JavaScript API](#javascript-api)
- [`log(message: string): void`](#log-message-string-void)
- [`log(section: string, message: string): void`](#log-section-string-message-string-void)
- [`log(section: string, traceId: string, message: string): void`](#log-section-string-traceid-string-message-string-void)
- [`log.err(...)`](#log-error)
- [`log.warn(...)`](#log-warn)
- [`log.info(...)`](#log-info)
- [`log.debug(...)`](#log-debug)
- [Using custom logging providers](#using-custom-logging-providers)
- [Developing custom logging providers](#developing-custom-logging-providers)
## Logging basics
Logging is a basic requirement for building services. `napajs` logging API enables developers to integrate their own logging capabilities in both JavaScript and C++ (addon) world.
A log row may contain following information:
- (Optional) Section: Useful as filter to treat different rows of logs. The treatment is defined by logging providers.
- (Optional) Trace ID: Useful field to join logs in the same transaction or request.
- (Required) Message: Log message.
- (Required) Logging level:
- Error: for application error.
- Warn: for warining information.
- Info: usually used for notifying service state change
- Debug: for debugging purpose
## C++ API
Include header: `<napa-log.h>`
Macros:
- LOG_ERROR(section, format, ...)
- LOG_ERROR_WITH_TRACEID(section, traceId, format, ...)
- LOG_WARNING(section, format, ...)
- LOG_WARNING_WITH_TRACEID(section, traceId, format, ...)
- LOG_INFO(section, format, ...)
- LOG_INFO_WITH_TRACEID(section, traceId, format, ...)
- LOG_DEBUG(section, format, ...)
- LOG_DEBUG_WITH_TRACEID(section, traceId, format, ...)
```cpp
#include <napa-log.h>
void MyFunction() {
// ...
LOG_ERROR("init", "error: %s", errorMessage.c_str());
}
```
## JavaScript API
### log(message: string): void
It logs a message. Using info level.
*Functions `log` are shortcuts for `log.info`.
Example:
```ts
import * as napa from 'napajs';
napa.log('program started');
```
### log(section: string, message: string): void
It logs a message with a section. Using info level.
Example:
```ts
napa.log('init', 'program started');
```
### log(section: string, traceId: string, message: string): void
It logs a message with a section, associating it with a traceId. Using info level.
Example:
```ts
napa.log('request', 'A1B2C3D4', 'request received');
```
### log.err(...)
It logs an error message. Three combinations of arguments are the same with `log`.
### log.warn(...)
It logs a warning message. Three combinations of arguments are the same with `log`.
### log.info(...)
It logs an info message. Three combinations of arguments are the same with `log`.
### log.debug(...)
It logs a debug message. Three combinations of arguments are the same with `log`.
## Using custom logging providers
Developers can hook up custom logging provider by calling the following before creation of any zones:
```ts
napa.runtime.setPlatformSettings({
"loggingProvider": "<custom-logging-provider-module-name>"
}
```
## Developing custom logging providers
TBD

Просмотреть файл

@ -1,55 +1,58 @@
# namespace `memory`
## Table of Contents
- type [`Handle`](#handle)
- class [`Buffer`](#buffer)
- interface [`Shareable`](#shareable)
- interface [`Allocator`](#allocator)
- [`allocator.allocate(size: number): Handle`](#allocator-allocate)
- [`allocator.deallocate(handle: Handle, sizeHint: number): void`](#allocator-deallocate)
- [`allocator.type: string`](#allocator-type)
- interface [`AllocatorDebugger`](#allocatorDebugger)
- [`allocatorDebugger.debugInfo: string`](#allocatorDebugger-debugInfo)
- [`debugAllocator(allocator: Allocator): AllocatorDebugger`]
- object [`crtAllocator`](#crtAllocator)
- object [`defaultAllocator`](#defaultAllocator)
- [Memory allocation in C++ addon](#memory-allocation)
- type [`Handle`](#type-handle)
- class [`Buffer`](#class-buffer)
- interface [`Shareable`](#interface-shareable)
- interface [`Allocator`](#interface allocator)
- [`allocator.allocate(size: number): Handle`](#allocator-allocate-size-number-handle)
- [`allocator.deallocate(handle: Handle, sizeHint: number): void`](#allocator-deallocate-handle-handle-sizehint-number-void)
- [`allocator.type: string`](#allocator-type-string)
- interface [`AllocatorDebugger`](#interface-allocatordebugger)
- [`allocatorDebugger.debugInfo: string`](#allocatordebugger-debugInfo-string)
- function [`debugAllocator(allocator: Allocator): AllocatorDebugger`](#debugallocator-allocator-allocator-allocatordebugger)
- object [`crtAllocator`](#object-crtallocator)
- object [`defaultAllocator`](#object-defaultallocator)
- [Memory allocation in C++ addon](#memory-allocation-in-c-addon)
## APIs
## <a name="handle"></a>Type `Handle`
## Type `Handle`
Handle is defined in TypeScript as below:
```ts
type Handle = [number, number]
```
It is a standard way to represent a 64-bit pointer in Napa.
## <a name="buffer"></a>Class `Buffer`
## Class `Buffer`
TBD
## <a name="allocator"></a>Interface `Allocator`
## Interface `Shareable`
Interface for native object wrap that can be shared across multiple JavaScript threads.
## Interface `Allocator`
Interface for memory allocator that allocates memory for native objects.
### <a name="allocator-allocate"></a>allocator.allocate(size: number): Handle
### allocator.allocate(size: number): Handle
It allocates memory of requested size.
```ts
let handle = allocator.allocate(10);
```
### <a name="allocator-deallocate"></a>allocator.deallocate(handle: Handle, sizeHint: number): void
### allocator.deallocate(handle: Handle, sizeHint: number): void
It deallocates memory from a input handle, with a size hint which is helpful for some C++ allocator implementations for deallocating memory.
```ts
allocator.deallocate(handle, 10);
```
### <a name="allocator-type"></a>allocator.type: string
### allocator.type: string
It gets a string type identifier for the allocator, which will be useful during debugging purpose.
## <a name="allocatorDebugger"></a>Interface `AllocatorDebugger`
## Interface `AllocatorDebugger`
`AllocatorDebugger` extends interface `Allocator`, with a readonly property `debugInfo` to expose debug information. Basically an allocator debugger will use a pass-in allocator for memory allocation, meanwhile intercepting it to keep track of allocation count and size.
### <a name="allocatorDebugger-debugInfo"></a>allocatorDebugger.debugInfo: string
### allocatorDebugger.debugInfo: string
It gets the debug information for allocation.
## <a name="debugAllocator"></a>debugAllocator(allocator: Allocator): AllocatorDebugger
## debugAllocator(allocator: Allocator): AllocatorDebugger
It returns a simple allocator debugger, which returns debug information like below:
```json
{
@ -59,19 +62,20 @@ It returns a simple allocator debugger, which returns debug information like bel
"deallocateSize": 912
}
```
## <a name="crtAllocator"></a>Object `crtAllocator`
## Object `crtAllocator`
It returns a C-runtime allocator from napa.dll. Its corresponding C++ part is `napa::memory::GetCrtAllocator()`.
## <a name="defaultAllocator"></a>Object `defaultAllocator`
## Object `defaultAllocator`
It returns the default allocator from napa.dll. Its corresponding C++ part is `napa::memory::GetDefaultAllocator()`. Users can set default allocation/deallocation callback in `napa_allocator_set` API.
## <a name="memory-allocation"></a>Memory allocation in C++ addon
## Memory allocation in C++ addon
Memory allocation in C++ addon is tricky. A common pitfall is to allocate memory in one dll, but deallocate in another. This can cause issue if C-runtime in these 2 dlls are not compiled the same way.
There are also advanced scenarios that user want to customize memory allocation. Napa provides APIs for customizing memory allocator as well.
### Recommended way of allocate memory.
TBD
### Customize memory allocation
TBD

185
docs/api/metric.md Normal file
Просмотреть файл

@ -0,0 +1,185 @@
# namespace `metric`
## Table of Contents
- [Metric basics](#metric-basics)
- [C++ API](#c-api)
- interface [`Metric`](#interface-metric)
- interface [`MetricProvider`](#interface-metric-provider)
- function [`MetricProvider& GetMetricProvider()`](#metricprovider-getmetricprovider)
- [JavaScript API](#javascript-api)(#javascript-api)
- enum [`MetricType`](#metrictype)
- class [`Metric`](#class-metric)
- [`set(value: number, dimensions?: string[]): void`](#set-value-number-dimensions-string)
- [`increment(dimensions?: string[]): void`]();
- [`decrement(dimensions?: string[]): void`]();
- function [`get(section: string, name: string, type: MetricType, dimensionNames: string[])`]()
- [Using custom metric providers](#using-custom-metric-providers)
- [Developing custom metric providers](#developing-custom-metric-providers)
## Metric basics
Similar as logging, metric a basic requirement for creating monitorable services. `napajs` metric API enables developers to use their own metric system in both JavaScript and C++ (addon) world.
A metric may contain following information:
- (Required) Section: The group or category of the metric.
- (Required) Name: Name of the metric. Section/Name combination should be unique in the system.
- (Required) Metric type: Type of the metric, which can be
- Number: A absolute number, e.g: PrivateBytes.
- Rate: A flowing volume in number, e.g: QueryPerSecond.
- Percentile: A absolute number that needs to be sampled by percentiles, e.g: SuccessLatency.
- (Required) Dimensions: A metric can have multiple dimensions, each dimension can bind with a string value at runtime. e.g: IncomingRequestRate can have 2 dimensions: ['client-id', 'request-type'].
## C++ API
### Interface Metric
```cpp
/// <summary> Enumeration of metric type. </summary>
enum class MetricType {
Number = 0,
Rate,
Percentile,
};
/// <summary> Interface to represents a multi-dimensional metric with a maximum dimensionality of 64. </summary>
class Metric {
public:
/// <summary> Sets a metric value with varidic dimension arguments. </summary>
/// <param name="value"> Int64 value. </param>
/// <param name="numberOfDimensions"> Number of dimensions being set. </param>
/// <param name="dimensionValues"> Array of dimension value names. </param>
/// <returns> Success/Fail. </returns>
/// <remarks>
/// The number of dimension values must exactly match the number of dimensions provided when
/// creating this metric.
/// </remarks>
virtual bool Set(int64_t value, size_t numberOfDimensions, const char* dimensionValues[]) = 0;
/// <summary>
/// Increments a metric value with variadic dimension arguments.
/// Use mainly to simplify rate counters.
/// </summary>
/// <param name="value"> UInt64 value to increment. </param>
/// <param name="numberOfDimensions"> Number of dimensions being set. </param>
/// <param name="dimensionValues"> Array of dimension value names. </param>
/// <returns> Success/Fail. </returns>
/// <remarks>
/// The number of dimension values must exactly match the number of dimensions
/// provided when creating this metric.
/// </remarks>
virtual bool Increment(uint64_t value, size_t numberOfDimensions, const char* dimensionValues[]) = 0;
/// <summary>
/// Decrements metric value with varidic dimension arguments.
/// Use mainly to simplify rate counters.
/// </summary>
/// <param name="value"> UInt64 value to decrement. </param>
/// <param name="numberOfDimensions"> Number of dimensions being set. </param>
/// <param name="dimensionValues"> Array of dimension value names. </param>
/// <returns> Success/Fail. </returns>
/// <remarks>
/// The number of dimension values must exactly match the number of dimensions
/// provided when creating this metric.
/// </remarks>
virtual bool Decrement(uint64_t value, size_t numberOfDimensions, const char* dimensionValues[]) = 0;
/// <summary> Explicitly destroys the Metric. </summary>
/// <remarks>
/// Consumers are not required to call this.
/// The MetricProvider owns this class and will automatically perform cleanup on shutdown.
/// </remarks>
virtual void Destroy() = 0;
protected:
///<summary> Prevent calling delete on the interface. Must use Destroy! </summary>
virtual ~Metric() = default;
};
```
### Interface MetricProvider
```cpp
/// <summary> Interface for a generic metric provider. </summary>
/// <remarks>
/// Ownership of this metric provider belongs to the shared library which created it. Hence the explicit
/// Destroy method in this class. To simplify memory management across multiple shared libraries, this class
/// can only be created via a factory method provided by the shared library. When it is no longer needed,
/// the caller may call Destroy() which will tell the shared library which created it to dispose of the object.
/// </remarks>
class MetricProvider {
public:
/// <summary>
/// Gets or creates a N-dimensional metric. Metric objects are owned and cached by this class.
/// Up to 64 dimensions may be used.</summary>
/// <param name="section"> Section of the metric.</param>
/// <param name="name"> Name of the metric.</param>
/// <param name="type"> Type of the metric.</param>
/// <param name="dimensions">
/// Number of dimensions requested for this metric.
/// Represents the size of the array passed in for p_dimensionNames.
/// </param>
/// <param name="dimensionNames"> Array of dimension names being requested for this metric.</param>
/// <remarks>
/// The IMetric class returned is owned and cached by this class.
/// Callers are not required to call destroy() on the Metric.
/// </remarks>
virtual Metric* GetMetric(
const char* section,
const char* name,
MetricType type,
size_t dimensions,
const char* dimensionNames[]) = 0;
///<summary> Explicitly destroys the metric provider. </summary>
virtual void Destroy() = 0;
protected:
///<summary> Prevent calling delete on the interface. Must use Destroy! </summary>
virtual ~MetricProvider() = default;
};
```
### function `MetricProvider& GetMetricProvider()`
```cpp
/// <summary> Exports a getter function for retrieves the configured metric provider. </summary>
NAPA_API MetricProvider& GetMetricProvider();
```
## JavaScript API
```ts
export enum MetricType {
Number = 0,
Rate,
Percentile,
}
export interface Metric {
section: string;
name: string;
set(value: number, dimensions?: string[]): void;
increment(dimensions?: string[]): void;
decrement(dimensions?: string[]): void;
}
export function get(
section: string,
name: string,
type: MetricType,
dimensions: string[] = []) : Metric;
```
Example:
```ts
import * as napa from 'napajs';
let metric = napa.metric.get('app1', 'counter1', napa.metric.MetricType.Number, []);
metric.increment([]);
```
## Using custom metric providers
Developers can hook up custom metric provider by calling the following before creation of any zones:
```ts
napa.runtime.setPlatformSettings({
"metricProvider": "<custom-metric-provider-module-name>"
}
```
## Developing custom metric providers
TBD

Просмотреть файл

Просмотреть файл

@ -1,32 +1,35 @@
# namespace `store`
## Table of Contents
- [`create(id: string): Store`](#create)
- [`get(id: string): Store`](#get)
- [`getOrCreate(id: string): Store`](#getOrCreate)
- [`count: number`](#count)
- interface [`Store`](#store)
- [`store.id: string`](#store-id)
- [`store.set(key: string, value: any): void`](#store-set)
- [`store.get(key: string): any`](#store-get)
- [`store.has(key: string): boolean`](#store-has)
- [`store.size: number`](#store-size)
- [Introduction to Store](#introduction-to-store)
- [API](#api)
- [`create(id: string): Store`](#create-id-string-store)
- [`get(id: string): Store`](#get-id-string-store)
- [`getOrCreate(id: string): Store`](#getOrCreate-id-string-store)
- [`count: number`](#count-number)
- interface [`Store`](#interface-store)
- [`store.id: string`](#store-id-string)
- [`store.set(key: string, value: any): void`](#store-set-key-string-value-any)
- [`store.get(key: string): any`](#store-get-key-string-any)
- [`store.has(key: string): boolean`](#store-has-key-string-boolean)
- [`store.size: number`](#store-size-number)
## APIs
Store API is introduced as a necessary complement of sharing [transportable](transport.md#transportable) objects across JavaScript threads, on top of passing objects via arguments. During `store.set`, values marshalled into JSON and stored in process heap, so all threads can access it, and unmarshalled while users retrieve them via `store.get`.
## Introduction to Store
Store API is introduced as a necessary complement of sharing [transportable](transport.md#transportable-types) objects across JavaScript threads, on top of passing objects via arguments. During `store.set`, values marshalled into JSON and stored in process heap, so all threads can access it, and unmarshalled while users retrieve them via `store.get`.
Though very convenient, it's not recommended to use store to pass values within a transaction or request, since its overhead is more than passing objects by arguments (there are extra locking, etc.). Besides, developers have the obligation to delete the key after usage, while it's automatically managed by reference counting in passing arguments.
## API
Following APIs are exposed to create, get and operate upon stores.
### <a name="create"></a>create(id: string): Store
### create(id: string): Store
It creates a store by a string identifer that can be used to get the store later. When all references to the store from all JavaScript VMs are cleared, the store will be destroyed. Thus always keep a reference at global or module scope is usually a good practice using `Store`. Error will be thrown if the id already exists.
Example:
```ts
let store = napa.store.create('store1');
```
### <a name="get"></a>get(id: string): Store
### get(id: string): Store
It gets a reference of store by a string identifier. `undefined` will be returned if the id doesn't exist.
Example:
@ -34,38 +37,38 @@ Example:
let store = napa.store.get('store1');
```
### <a name="getOrCreate"></a>getOrCreate(id: string): Store
### getOrCreate(id: string): Store
It gets a reference of store by a string identifier, or creates it if the id doesn't exist. This API is handy when you want to create a store in code that is executed by every worker of a zone, since it doesn't break symmetry.
Example:
```ts
let store = napa.store.getOrCreate('store1');
```
### <a name="count"></a>count: number
### count: number
It returns count of living stores.
### <a name="store"></a>interface `Store`
### Interface `Store`
Interface that let user to put and get objects across multiple JavaScript VMs.
### <a name="store-id"></a>store.id: string
### store.id: string
It gets the string identifier for the store.
### <a name="store-set"></a>store.set(key: string, value: any): void
It puts a [transportable](transport.md#transportable) value into store with a string key. If key already exists, new value will override existing value.
### store.set(key: string, value: any): void
It puts a [transportable](transport.md#transportable-types) value into store with a string key. If key already exists, new value will override existing value.
Example:
```ts
store.set('status', 1);
```
### <a name="store-get"></a>store.get(key: string): any
It gets a [transportable](transportable.md#transportable) value from the store by a string key. If key doesn't exist, `undefined` will be returned.
### store.get(key: string): any
It gets a [transportable](transportable.md#transportable-types) value from the store by a string key. If key doesn't exist, `undefined` will be returned.
Example:
```ts
let value = store.get('status');
assert(value === 1);
```
### <a name="store-has"></a>store.has(key: string): boolean
### store.has(key: string): boolean
It tells if a key exists in current store.
Example:
@ -73,5 +76,5 @@ Example:
assert(store.has('status'))
```
### <a name="store-size"></a>store.size: number
### store.size: number
It tells how many keys are stored in current store.

Просмотреть файл

@ -1,21 +1,21 @@
# namespace `sync`
## Table of Contents
- class [`Lock`](#lock)
- [`lock.guard(func: () => any): any`](#lock-guard)
- class [`ReadWriteLock`](#rwlock)
- [`rwlock.guardRead(func: () => any): any`](#rwlock-guardRead)
- [`rwlock.guardWrite(func: () => any): any`](#rwlock-guardWrite)
- class [`Lock`](#class-lock)
- [`lock.guard(func: () => any): any`](#lock-guard-func-any-any)
- class [`ReadWriteLock`](#class-readwritelock)
- [`rwlock.guardRead(func: () => any): any`](#rwlock-guardread-func-any-any)
- [`rwlock.guardWrite(func: () => any): any`](#rwlock-guardwrite-func-any-any)
## APIs
Namespace `sync` deal with synchronization between threads in Napa. `Lock` and `ReadWriteLock` are provided for exclusive and shared mutex scenarios.
## <a name="lock"></a> Class `Lock`
## Class `Lock`
Exclusive Lock, which is [transportable](transport.md#transportable) across JavaScript threads.
Example: Creating a lock with operator `new`.
```ts
let lock = new napa.sync.Lock();
```
### <a name="lock-guard"></a> lock.guard(func: () => any): any
### lock.guard(func: () => any): any
Run input function synchronously and obtain the lock during its execution, returns what the function returns, or throws error if input function throws. Lock will be released once execution finishes.
```ts
try {
@ -29,7 +29,7 @@ catch(error) {
console.log(error);
}
```
## <a name="rwlock"></a> Class `ReadWriteLock`
## Class `ReadWriteLock`
Read-write lock, which is [transportable](transport.md#transportable) across JavaScript threads.
Example: Creating a read-write lock with operator `new`.
@ -37,7 +37,7 @@ Example: Creating a read-write lock with operator `new`.
let lock = new napa.sync.ReadWriteLock();
```
### <a name="rwlock-guardRead"></a> rwlock.guardRead(func: () => any): any
### rwlock.guardRead(func: () => any): any
Run input function synchronously and obtain the read (shared) lock during its execution, returns what the function returns, or throws error if input function throws. Read lock will be released once execution finishes. Multiple guardRead across threads can enter simutenously while no pending guardWrite.
```ts
@ -53,7 +53,7 @@ catch(error) {
}
```
### <a name="rwlock-guardWrite"></a> rwlock.guardWrite(func: () => any): any
### rwlock.guardWrite(func: () => any): any
Run input function synchronously and obtain the write (exclusive) lock during its execution, returns what the function returns, or throws error if input function throws. Write lock will be released once execution finishes. Multiple guardWrite across threads cannot entered simutenously, and will always wait if there is any pending guardRead.

Просмотреть файл

@ -1,54 +1,58 @@
# namespace `transport`
## Table of Contents
- [Transporting JavaScript values](#transport)
- [`isTransportable(jsValue: any): boolean`](#isTransportable)
- [`register(transportableClass: new(...args: any[]) => any): void`](#register)
- [`marshallTransform(jsValue: any, context: TransportContext): any`](#marshallTransform) (unstable)
- [`marshall(jsValue: any, context: TransportContext): string`](#marshall)
- [`unmarshall(json: string, context: TransportableContext): any`](#unmarshall)
- class [`TransportContext`](#transportContext)
- [`context.saveShared(object: memory.Shareable): void`]
- [`context.loadShared(handle: memory.Handle): memory.Shareable`]
- [`context.sharedCount: number`]
- interface [`Transportable`](#transportable)
- [`transportable.cid: string`](#transportable-cid)
- [`transportable.marshall(context: TransportContext): object`](#transportable-marshall)
- [`transportable.unmarshall(payload: object, context: TransportContext): void`](#transportable-unmarshall)
- abstract class [`TransportableObject`](#transportableObject)
- [`transportableObject.cid: string`](#transportableObject-cid)
- [`transportableObject.marshall(context: TransportContext): object`](#transportableObject-marshall)
- [`transportableObject.unmarshall(payload: object, context: TransportContext): void`](#transportableObject-unmarshall)
- abstract [`transportableObject.save(payload: object, context: TransportContext): void`](#transportableObject-save)
- abstract [`transportableObject.load(payload: object, context: TransportContext): void`](#transportableObject-load)
- class [`AutoTransportable`](#autoTransportable)
- decorator [`cid`](#cid-decorator)
- [Implementing user transportable classes](#implement)
- [Transporting JavaScript values](#transporting-javascript-values)
- [Transportable types](#transportable-types)
- [Constructor ID](#constructor-id)
- [Transport context](#transport-context)
- API
- [`isTransportable(jsValue: any): boolean`](#istransportable-jsvalue-any)
- [`register(transportableClass: new(...args: any[]) => any): void`](#register-transportableclass-new-args-any-any-void)
- [`marshallTransform(jsValue: any, context: TransportContext): any`](#marshalltransform-jsvalue-any-context-transportcontext-any) (unstable)
- [`marshall(jsValue: any, context: TransportContext): string`](#marshall-jsvalue-any-context-transportcontext-string)
- [`unmarshall(json: string, context: TransporteContext): any`](#unmarshall-json-string-context-transportecontext-any)
- class [`TransportContext`](#class-transportcontext)
- [`context.saveShared(object: memory.Shareable): void`](context-saveshared-object-memory-shareable-void)
- [`context.loadShared(handle: memory.Handle): memory.Shareable`](context-loadshared-handle-memory-handle-shareable)
- [`context.sharedCount: number`](context-sharedcount-number)
- interface [`Transportable`](#interface-transportable)
- [`transportable.cid: string`](#transportable-cid-string)
- [`transportable.marshall(context: TransportContext): object`](#transportable-marshall-context-transportcontext-object)
- [`transportable.unmarshall(payload: object, context: TransportContext): void`](#transportable-unmarshall-payload-object-context-transportcontext-void)
- abstract class [`TransportableObject`](#abstract-class-transportableobject)
- [`transportableObject.cid: string`](#transportableobject-cid-string)
- [`transportableObject.marshall(context: TransportContext): object`](#transportableobject-marshall-context-transportcontext-object)
- [`transportableObject.unmarshall(payload: object, context: TransportContext): void`](#transportableobject-unmarshall-payload-object-context-transportcontext-void)
- abstract [`transportableObject.save(payload: object, context: TransportContext): void`](#abstract-transportableobject-save-payload-object-context-transportcontext-void)
- abstract [`transportableObject.load(payload: object, context: TransportContext): void`](#abstract-transportableobject-load-payload-object-context-transportcontext-void)
- class [`AutoTransportable`](#class-autotransportable)
- decorator [`cid`](#decorator-cid)
- [Implementing user transportable classes](#implementing-user-transportable-classes)
## <a name="transport"></a>Transporting JavaScript values
## Transporting JavaScript values
Existing JavaScript engines are not designed for running JavaScript across multiple VMs, which means every VM manages their own heap. Passing values from one VM to another has to be marshalled/unmarshalled. The size of payload and complexity of object will greatly impact communication efficiency. In Napa, we try to work out a design pattern for efficient object sharing, based on the fact that all JavaScript VMs (exposed as workers) reside in the same process, and native objects can be wrapped and exposed as JavaScripts objects.
Following concepts are introduced to implement this pattern:
### Transportable types
Transportable types are JavaScript types that can be passed or shared transparently across Napa workers. They are used as value types for passing arguments in [`zone.broadcast`](zone.md#broadcast-function) / [`zone.execute`](zone.md#execute-function), and sharing objects in key/value pairs via [`store.set`](store.md#store-set) / [`store.get`](store.md#store-get).
Transportable types are JavaScript types that can be passed or shared transparently across Napa workers. They are used as value types for passing arguments in [`zone.broadcast`](zone.md#broadcast-function) / [`zone.execute`](zone.md#execute-function), and sharing objects in key/value pairs via [`store.set`](store.md#store-set-key-string-value-any) / [`store.get`](store.md#store-get-key-string-any).
Transportable types are:
- JavaScript primitive types: undefined, null, boolean, number, string
- Object (TypeScript class) that implement [`Transportable`](#transportable) interface
- Object (TypeScript class) that implement [`Transportable`](#interface-transportable) interface
- Array or plain JavaScript object that is composite pattern of above.
### <a name="cid"></a>Constructor ID (cid)
For user classes that implement [`Transportable`](#transportable) interface, Napa uses Constructor ID (`cid`) to lookup constructors for creating a right object from a string payload. `cid` is marshalled as a part of the payload. During unmarshalling, transport layer will extract the `cid`, create an object instance using the constructor associated with it, and then call unmarshall on the object.
### Constructor ID (cid)
For user classes that implement [`Transportable`](#interface-transportable) interface, Napa uses Constructor ID (`cid`) to lookup constructors for creating a right object from a string payload. `cid` is marshalled as a part of the payload. During unmarshalling, transport layer will extract the `cid`, create an object instance using the constructor associated with it, and then call unmarshall on the object.
It's class developer's responsibility to choose the right `cid` for your class. To avoid conflict, we suggest to use the combination of module.id and class name as `cid`. Developer can use class decorator [`cid`](#cid-decorator) to register a user Transportable class automatically, when using TypeScript with decorator feature enabled. Or call [`transport.register`](#register) manually during module initialization.
It's class developer's responsibility to choose the right `cid` for your class. To avoid conflict, we suggest to use the combination of module.id and class name as `cid`. Developer can use class decorator [`cid`](#decorator-cid) to register a user Transportable class automatically, when using TypeScript with decorator feature enabled. Or call [`transport.register`](#register-transportableclass-new-args-any-any-void) manually during module initialization.
### <a name="transportContext"></a>Transport context
### Transport context
There are states that cannot be saved or loaded in serialized form (like std::shared_ptr), or it's very inefficient to serialize (like JavaScript function). Transport context is introduced to help in these scenarios. TransportContext objects can be passed from one JavaScript VM to another, or stored in native world, so lifecycle of shared native objects extended by using TransportContext. An example of `Transportable` implementation using TransportContext is [`ShareableWrap`](..\..\inc\napa\module\shareable-wrap.h).
## API
### <a name="isTransportable"></a>isTransportable(jsValue: any): boolean
### isTransportable(jsValue: any): boolean
It tells whether a JavaScript value is transportable or not.
```ts
// JS primitives
@ -85,7 +89,7 @@ class B {
// Not transportable JS class. (not registered with @cid).
assert(!transport.isTransportable(new B()));
```
### <a name="register"></a>register(transportableClass: new(...args: any[]) => any): void
### register(transportableClass: new(...args: any[]) => any): void
Register a `Transportable` class before transport layer can marshall/unmarshall its instances.
User can also use class decorator [`@cid`](#cid-decorator) for class registration.
@ -101,7 +105,7 @@ class A extends transport.AutoTransportable {
// Explicitly register class A in transport.
transport.register(A);
```
### <a name="marshallTransform"></a>marshallTransform(jsValue: any, context: TransportContext): any
### marshallTransform(jsValue: any, context: TransportContext): any
*unstable - may change in future iterations
Performing marshalling transform on an arbitary JavaScript value, if input is transportable, a plain JavaScript value will be returned. Otherwise an error will be thrown.
@ -122,8 +126,8 @@ class SomeClass extends transport.TransportableObject {
//...
}
```
### <a name="marshall"></a>marshall(jsValue: any, context: TransportContext): string
Marshall a [transportable](#transportable) JavaScript value into a JSON payload with a [`TransportContext`](#transportContext). Error will be thrown if the value is not transportable.
### marshall(jsValue: any, context: TransportContext): string
Marshall a [transportable](#transportable-types) JavaScript value into a JSON payload with a [`TransportContext`](#transport-context). Error will be thrown if the value is not transportable.
Example:
```ts
@ -131,40 +135,40 @@ let context = transport.createTransportContext();
let jsonPayload = transport.marshall([1, 'string', napa.memory.crtAllocator], context);
console.log(jsonPayload);
```
### <a name="unmarshall"></a>unmarshall(json: string, context: TransportableContext): any
Unmarshall an [transportable](#transportable) JavaScript value from a JSON payload with a [`TransportContext`](#transportContext). Error will be thrown if `cid` property is found and not registered with transport layer.
### unmarshall(json: string, context: TransportContext): any
Unmarshall an [transportable](#transportable-types) JavaScript value from a JSON payload with a [`TransportContext`](#transport-context). Error will be thrown if `cid` property is found and not registered with transport layer.
Example:
```ts
let value = transport.unmarshall(jsonPayload, context);
```
## <a name="transportContext-class"></a>Class `TransportContext`
Class for [Transport Context](#transportContext), that stores shared pointers and functions during marshall/unmarshall.
### <a name="context-saveShared"></a> context.saveShared(object: memory.Shareable): void
## Class `TransportContext`
Class for [Transport Context](#transport-context), that stores shared pointers and functions during marshall/unmarshall.
### context.saveShared(object: memory.Shareable): void
Save a shareable object in context.
### <a name="context-loadShared"></a> context.loadShared(handle: memory.Handle): memory.Shareable
### context.loadShared(handle: memory.Handle): memory.Shareable
Load a shareable object from handle.
### <a name="context-sharedCount"></a> context.sharedCount: number
### context.sharedCount: number
Count of shareable objects saved in current context.
## <a name="transportable"></a>Interface `Transportable`
## Interface `Transportable`
Interface for Transportable object.
### <a name="transportable-cid"></a>transportable.cid: string
Get accessor for [Constructor ID](#cid). It is used to lookup constructor for payload of current class.
### transportable.cid: string
Get accessor for [Constructor ID](#constructor-id). It is used to lookup constructor for payload of current class.
### <a name="transportable-marshall"></a>transportable.marshall(context: TransportContext): object
Marshall transform this object into a plain JavaScript object with the help of [TransportContext](#transportContext).
### transportable.marshall(context: TransportContext): object
Marshall transform this object into a plain JavaScript object with the help of [TransportContext](#transport-context).
### <a name="transportable-unmarshall"></a>transportable.unmarshall(payload: object, context: TransportContext): void
### transportable.unmarshall(payload: object, context: TransportContext): void
Unmarshall transform marshalled payload into current object.
## <a name="transportableObject"></a>Abstract class `TransportableObject`
### <a name="cid-decorator"></a>Decorator `cid`
## Abstract class `TransportableObject`
### Decorator `cid`
## <a name="implement"></a>Implementing User Transportable Classes
## Implementing User Transportable Classes
### JavaScript class
#### Extending TransportableObject
### Addon class

Просмотреть файл

@ -1,33 +1,33 @@
# namespace `zone`
## Table of Contents
- [`create(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#create)
- [`getOrCreate(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#getOrCreate)
- [`get(id: string): Zone`](#get)
- [`current: Zone`](#current)
- [`node: Zone`](#node)
- interface [`ZoneSettings`](#zoneSettings)
- [`settings.workers: number`](#settings-workers)
- [`DEFAULT_SETTINGS: ZoneSettings`](#defaultSettings)
- 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.broadcastSync(code: string): void`](#broadcastSync-code)
- [`zone.broadcastSync(function: (...args: any[]) => void, args: any[]): void`](#broadcastSnc-function)
- [`zone.execute(moduleName: string, functionName: string, args: any[], timeout: number): Promise<any>`](#execute-name)
- [`zone.execute(function: (...args[]) => any, args: any[], timeout: number): Promise<any>`](#execute-function)
- [`zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number): any`](#executeSync-name)
- [`zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number): any`](#executeSync-function)
- interface [`ExecuteResult`](#executeResult)
- [`result.value: any`](#result-value)
- [`result.payload: string`](#result-payload)
- [`result.transportContext: transport.TransportContext`](#result-transportContext)
- [`create(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#create-id-string-settings-zonesettings-default_settings-zone)
- [`getOrCreate(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zone`](#getOrCreate-id-string-settings-zonesettings-default_settings-zone)
- [`get(id: string): Zone`](#get-id-string-zone)
- [`current: Zone`](#current-zone)
- [`node: Zone`](#node-zone)
- interface [`ZoneSettings`](#interface-zonesettings)
- [`settings.workers: number`](#settings-workers-number)
- object [`DEFAULT_SETTINGS: ZoneSettings`](#object-default_settings-zonesettings)
- interface [`Zone`](#interface-zone)
- [`zone.id: string`](#zone-id-string)
- [`zone.broadcast(code: string): Promise<void>`](#zone-broadcast-code-string-promise-void)
- [`zone.broadcast(function: (...args: any[]) => void, args: any[]): Promise<void>`](#zone-broadcast-function-args-any-void-args-any-promise-void)
- [`zone.broadcastSync(code: string): void`](#zone-broadcastsync-code-string-void)
- [`zone.broadcastSync(function: (...args: any[]) => void, args: any[]): void`](#zone-broadcastsync-function-args-any-void-args-any-void)
- [`zone.execute(moduleName: string, functionName: string, args: any[], timeout: number): Promise<ExecuteResult>`](#zone-execute-modulename-string-functionname-string-args-any-timeout-number-promise-executeresult)
- [`zone.execute(function: (...args[]) => any, args: any[], timeout: number): Promise<ExecuteResult>`](#zone-execute-function-args-any-args-any-timeout-number-promise-executeresult)
- [`zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number): ExecuteResult`](#zone-executesync-modulename-string-functionname-string-args-any-timeout-number-executeresult)
- [`zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number): ExecuteResult`](#zone-executesync-function-args-any-any-args-any-timeout-number-executeresult)
- interface [`ExecuteResult`](#interface-executeresult)
- [`result.value: any`](#result-value-any)
- [`result.payload: string`](#result-payload-string)
- [`result.transportContext: transport.TransportContext`](#result-transportcontext-transport-transportcontext)
## API
### <a name="create"></a>create(id: string, settings: ZoneSettings): Zone
### create(id: string, settings: ZoneSettings): Zone
It creates a Napa zone with a string id. If zone with the id is already created, error will be thrown. [`ZoneSettings`](#zoneSettings) can be specified for creating zones.
It creates a Napa zone with a string id. If zone with the id is already created, error will be thrown. [`ZoneSettings`](#interface-zonesettings) can be specified for creating zones.
Example 1: Create a zone with id 'zone1', using default ZoneSettings.
```ts
@ -40,7 +40,7 @@ let zone = napa.zone.create('zone1', {
workers: 1
});
```
### <a name="getOrCreate"></a>getOrCreate(id: string, settings: ZoneSettings): Zone
### getOrCreate(id: string, settings: ZoneSettings): Zone
It gets a reference of zone by an id if a zone with the id already exists, otherwise create a new one and return its reference.
Example:
@ -49,48 +49,48 @@ let zone = napa.zone.getOrCreate('zone1', {
workers: 4
});
```
### <a name="get"></a>get(id: string): Zone
### get(id: string): Zone
It gets a reference of zone by an id. Error will be thrown if the zone doesn't exist.
Example:
```ts
let zone = napa.zone.get('zone1');
```
### <a name="current"></a>current: Zone
### current: Zone
It returns a reference of the zone of current running isolate. If it's under node, it returns the [node zone](#node).
Example: Get current zone.
```ts
let zone = napa.zone.current;
```
### <a name="node"></a>node: Zone
### node: Zone
It returns a reference to the node zone. It is equivalent to `napa.zone.get('node')`;
Example:
```ts
let zone = napa.zone.node;
```
## <a name="zoneSettings"></a>Interface `ZoneSettings`
Settings for zones, which will be specified during creation of zones. If not specified, [DEFAULT_SETTINGS](#defaultSettings) will be used.
## Interface `ZoneSettings`
Settings for zones, which will be specified during creation of zones. If not specified, [DEFAULT_SETTINGS](#object-defaultSettings) will be used.
### <a name="settings-workers"></a>settings.workers: number
### settings.workers: number
Number of workers in the zone.
## <a name="defaultSettings"></a>DEFAULT_SETTINGS
## Object `DEFAULT_SETTINGS`
Default settings for creating zones.
```ts
{
workers: 2
}
```
## <a name="zone"></a>Interface `Zone`
Zone is the basic concept to execute JavaScript and apply policies in Napa. You can find its definition in [Architecture](../../README.md#Architecture). Through Zone API, developers can broadcast JavaScript code on all workers, or execute a function on one of them. When you program against a zone, it is the best practice to ensure all workers within a zone are symmetrical to each other, that you should not assume a worker may maintain its own states.
## Interface `Zone`
Zone is the basic concept to execute JavaScript and apply policies in Napa. You can find its definition in [Architecture](../../README.md#architecture). Through Zone API, developers can broadcast JavaScript code on all workers, or execute a function on one of them. When you program against a zone, it is the best practice to ensure all workers within a zone are symmetrical to each other, that you should not assume a worker may maintain its own states.
The two major set of APIs are `broadcast` and `execute`, with both synchronous and asynchronous version plus a few variations on their inputs.
### <a name="zone-id"></a>zone.id: string
### zone.id: string
It gets the id of the zone.
### <a name="broadcast-code"></a>zone.broadcast(code: string): Promise\<void\>
### zone.broadcast(code: string): Promise\<void\>
It asynchronously broadcasts a snippet of JavaScript code in a string 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.
Example:
@ -105,7 +105,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\>
### zone.broadcast(function: (...args: any[]) => void, args: any[]): Promise\<void\>
It asynchronously broadcasts an annoymous 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.
@ -123,7 +123,7 @@ zone.broadcast((state) => {
console.log('broadcast failed:', error)
});
```
### <a name="broadcastSync-code"></a>zone.broadcastSync(code: string): void
### zone.broadcastSync(code: string): void
It synchronously broadcasts a snippet of JavaScript code in a string to all workers. If any of the workers failed to execute the code, an error will be thrown with message.
Example:
@ -136,7 +136,7 @@ catch (error) {
console.log('broadcast failed:', error);
}
```
### <a name="broadcastSync-function"></a>zone.broadcastSync(function: (...args: any[]) => void, args: any[]): void
### zone.broadcastSync(function: (...args: any[]) => void, args: any[]): void
It synchronously broadcasts an annoymous function with its arguments to all workers. If any of the workers failed to execute the code, an error will be thrown with message.
@ -153,8 +153,8 @@ catch (error) {
console.log('broadcast failed:', error);
}
```
### <a name="execute-name"></a>zone.execute(moduleName: string, functionName: string, args: any[], timeout: number = 0): 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). It returns a Promise of [`ExecuteResult`](#executeResult). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
### zone.execute(moduleName: string, functionName: string, args: any[], timeout: number = 0): 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 [`ExecuteResult`](#interface-executeresult). 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.
```ts
@ -168,9 +168,9 @@ zone.execute('foo', 'bar', [1, "hello", {field1: 1}], 300)
```
### <a name="execute-function"></a>zone.execute(function: (...args: any[]) => any, args: any[], timeout: number = 0): Promise\<any\>
### zone.execute(function: (...args: any[]) => any, args: any[], timeout: number = 0): Promise\<any\>
Execute an anonymous function asynchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable). It returns a Promise of [`ExecuteResult`](#executeResult). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
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 [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
Example:
```ts
@ -186,9 +186,9 @@ zone.execute((a: number, b: string, c: object) => {
```
### <a name="executeSync-name"></a>zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number = 0): any
### zone.executeSync(moduleName: string, functionName: string, args: any[], timeout: number = 0): any
Execute a function synchronously on arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable). It returns an [`ExecuteResult`](#executeResult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
Execute a function synchronously 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 an [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
Example: Execute function 'bar' in module 'foo', with arguments [1, 'hello', { field1: 1 }]. 300ms timeout is applied.
```ts
@ -202,8 +202,8 @@ catch (error) {
```
### <a name="executeSync-function"></a>zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number = 0): any
Execute an annoymouse function synchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable). It returns an [`ExecuteResult`](#executeResult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
### zone.executeSync(function: (...args: any[]) => any, args: any[], timeout: number = 0): any
Execute an annoymouse function synchronously on arbitrary worker. Arguments can be of any JavaScript type that is [transportable](transport.md#transportable-types). It returns an [`ExecuteResult`](#interface-executeresult). If error happens, either bad code, user exception, or timeout is reached, error will be thrown.
Example: Execute annoymouse function sychronously, with arguments [1, 'hello', { field1: 1 }]. No timeout is applied.
```ts
@ -219,18 +219,18 @@ catch (error) {
```
## <a name="executeResult"></a>Interface `ExecuteResult`
## Interface `ExecuteResult`
Interface to access return value of `zone.execute` or `zone.executeSync`.
### <a name="result-value"></a>result.value: any
JavaScript value returned from function which is invoked from zone.execute/executeSync. Napa marshall/unmarshall [transportable values](transport.md#transportable) between different workers (V8 isolates). Unmarshalling will happen when the first `result.value` is queried.
### result.value: any
JavaScript value returned from function which is invoked from zone.execute/executeSync. Napa marshall/unmarshall [transportable values](transport.md#transportable-types) between different workers (V8 isolates). Unmarshalling will happen when the first `result.value` is queried.
Example:
```ts
let value = result.value;
```
### <a name="result-payload"></a>result.payload: string
### result.payload: string
Marshalled payload (in JSON) from returned value. This field is for users that want to pass result through to its caller, where unmarshalled value is not required.
Example:
@ -238,8 +238,8 @@ Example:
let payload = result.payload;
```
### <a name="result-transportContext"></a>result.transportContext: transport.TransportContext
[TransportContext](transport.md#transportContext) that is required to unmarshall [`result.payload`](#result-payload) into [`result.value`](#result-value).
### result.transportContext: transport.TransportContext
[TransportContext](transport.md#transport-context) that is required to unmarshall [`result.payload`](#result-payload-string) into [`result.value`](#result-value-any).
Example:
```ts

Просмотреть файл

@ -1,53 +0,0 @@
# Napa.JS Built-ins and Core Modules
## Node.JS compatible APIs
- fs
- fs.readFileSync (SUPPORTED)
- fs.writeFileSync (SUPPORTED)
- others (TBD)
- path (consider use Node.JS' implementation)
- events
- Class: EventEmitter
- stream (TBD)
- assert (TBD)
- assert(value[, message])
- assert.deepEqual
- assert.deepStrictEqual
- assert.doesNotThrow
- assert.equal
- assert.fail
- assert.ifError
- assert.notDeepEqual
- assert.notDeepStrictEqual
- assert.notEqual
- assert.notStrictEqual
- assert.ok
- assert.strictEqual
- assert.throws
- Global Objects
- Class: Buffer (TBD)
- __dirname (SUPPORTED)
- __pathname (SUPPORTED)
- console
- console.assert
- console.dir
- console.error
- console.info
- console.log (SUPPORTED)
- console.time
- console.timeEnd
- console.trace
- console.warn
- exports
- global (TBD)
- module
- process (TBD)
- require
- setImmediate (TBD)
- setInterval (TBD)
- setTimeout (TBD)
## Napa specific APIs
- global readonly variable '*__in_napa_container*': Tell if current code is running under a Napa.JS container.

Просмотреть файл

@ -1,3 +0,0 @@
# Napa.JS Container
TBD

Просмотреть файл

@ -1,3 +0,0 @@
# Napa.JS Module System
TODO:

Просмотреть файл

@ -1,3 +0,0 @@
# Building C++ Add-ons for Napa.JS
TODO:

Просмотреть файл

@ -1,3 +0,0 @@
# Coding under Visual Studio Code
TODO:

Просмотреть файл

@ -1,3 +0,0 @@
# Debugging Napa.JS modules
TODO:

Просмотреть файл

@ -1,7 +0,0 @@
# Napa.JS Embedders' Guide
## Embedding Napa.JS to a C++ process
TODO:
## Embedding Napa.JS to a C# process
TODO:

Просмотреть файл

@ -1,7 +1,7 @@
# Best practices writing dual-interface modules.
Dual-interface modules are Napa modules that expose both JavaScript and C++ interfaces. The major purpose of introducing a dual-interface module can be one of the following, or both:
1) Sharing C++ objects between host process and Napa add-ons without marshalling/unmarshalling.
1) Sharing C++ objects between host process and Napa add-ons without extensive marshalling/unmarshalling.
2) Provide 2 implementations - Javascript for agility, and C++ for performance. Developers can quickly iterate ideas in JavaScript, once logic is finalized, we can use C++ interfaces to hook up pretty easily.
## Pitfalls in dual-interface modules.

Просмотреть файл

@ -7,28 +7,28 @@ export enum MetricType {
}
export interface Metric {
section: string;
name: string;
readonly section: string;
readonly name: string;
set(value: number, dimensions?: string[]): void;
increment(value: number, dimensions?: string[]): void;
decrement(value: number, dimensions?: string[]): void;
increment(dimensions?: string[]): void;
decrement(dimensions?: string[]): void;
}
/// <summary> A cache for metric wraps. </summary>
var _metricsCache: { [key: string]: Metric } = {};
export function get(section: string, name: string, type: MetricType, dimensions: string[] = []) : Metric {
let key: string = (section ? section : "") + "_" + (name ? name : "");
let key: string = (section ? section : "") + "\\" + (name ? name : "");
// Check cache first
let metricWrap: Metric = _metricsCache[key];
if (metricWrap) {
return metricWrap;
let metric: Metric = _metricsCache[key];
if (metric) {
return metric;
}
// Add to cache
metricWrap = new binding.MetricWrap(section, name, type, dimensions);
let metricWrap: any = new binding.MetricWrap(section, name, type, dimensions);
metricWrap.section = section;
metricWrap.name = name;
_metricsCache[key] = metricWrap;