New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

n-api: implement promise #14365

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
7 participants
@gabrielschulhof
Contributor

gabrielschulhof commented Jul 19, 2017

Promise is implemented as a pair of objects. napi_create_promise()
returns both a JavaScript promise and a "deferred" in its out-params.
The deferred is linked to the promise such that the deferred can be
passed to napi_conclude_deferred() to rejct/resolve the promise. The
deferred is a valid JavaScript value, but it is a shell object offering
no useful JavaScript functionality. In contrast, the promise returned
by napi_create_promise() is a full-fledged native JavaScript Promise
which can be used for chaining in JavaScript.

napi_is_promise() can be used to check if a napi_value is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

n-api

@TimothyGu

The deferred wrapping is beautiful. LGTM, except a few nits.

Show outdated Hide outdated src/node_api.cc
Show outdated Hide outdated src/node_api.cc
Show outdated Hide outdated src/node_api.cc
napi_property_descriptor descriptors[] = {
DECLARE_NAPI_PROPERTY("createPromise", createPromise),
DECLARE_NAPI_PROPERTY("concludeCurrentPromise", concludeCurrentPromise),
DECLARE_NAPI_PROPERTY("isPromise", isPromise),

This comment has been minimized.

@TimothyGu

TimothyGu Jul 19, 2017

Member

There should be an anti-case for passing a promise to napi_conclude_deferred().

@TimothyGu

TimothyGu Jul 19, 2017

Member

There should be an anti-case for passing a promise to napi_conclude_deferred().

This comment has been minimized.

@gabrielschulhof
@gabrielschulhof
@TimothyGu

This comment has been minimized.

Show comment
Hide comment
@TimothyGu

TimothyGu Jul 19, 2017

Member

This PR inspired me to think of a potentially better idea for object wrapping. Please take a look: #14367

Member

TimothyGu commented Jul 19, 2017

This PR inspired me to think of a potentially better idea for object wrapping. Please take a look: #14367

- `[in] env`: The environment that the API is invoked under.
- `[in] promise`: The promise to examine
- `[out] is_promise`: Flag indicating whether `promise` is a native promise

This comment has been minimized.

@benjamingr

benjamingr Jul 19, 2017

Member

As someone who has helped maintain large promise libraries - I'm totally fine with making people Promise.resolve promises they pass to napi_* methods.

@benjamingr

benjamingr Jul 19, 2017

Member

As someone who has helped maintain large promise libraries - I'm totally fine with making people Promise.resolve promises they pass to napi_* methods.

This comment has been minimized.

@gabrielschulhof

gabrielschulhof Jul 19, 2017

Contributor

What do you mean by "I'm totally fine making people Promise.resolve promises"? Do you mean that you don't mind if the native side resolves a promise created in JS and then passed to the native side?

@gabrielschulhof

gabrielschulhof Jul 19, 2017

Contributor

What do you mean by "I'm totally fine making people Promise.resolve promises"? Do you mean that you don't mind if the native side resolves a promise created in JS and then passed to the native side?

This comment has been minimized.

@benjamingr

benjamingr Jul 20, 2017

Member

@gabrielschulhof I mean I'm fine with is_promise only caring about and working with native promises - and ignoring non-native promises in n-api completely

@benjamingr

benjamingr Jul 20, 2017

Member

@gabrielschulhof I mean I'm fine with is_promise only caring about and working with native promises - and ignoring non-native promises in n-api completely

@benjamingr

I started reviewing it - but I'm not sure about several more general things API wise in this PR - the API we're exposing seems complicated.

What about exporting the following instead?

napi_create_promise(env, *promise); // no deferred
napi_promise_resolve(env, *promise, *value); 
napi_promise_reject(env, *promise, *reason); 

We also need to consider what happens if a promise is passed as a fulfillment value (the state should be assimilated).

@TimothyGu

This comment has been minimized.

Show comment
Hide comment
@TimothyGu

TimothyGu Jul 19, 2017

Member

@benjamingr Some context about the deferred object is in an earlier iteration of the PR (#13717). +1 about nested promises though, going to need some tests for that.

Member

TimothyGu commented Jul 19, 2017

@benjamingr Some context about the deferred object is in an earlier iteration of the PR (#13717). +1 about nested promises though, going to need some tests for that.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Jul 19, 2017

Contributor

@benjamingr the V8 implementation provides two objects: a resolver and a promise. Now, it's true that they are in reality one and the same object, but that's an implementation detail that the API does not document. The v8 API certainly suggests that, given a random v8::Promise we need the corresponding v8::Promise::Resolver to resolve it.

So, if somebody passes in a v8::Promise from the JS side, we must be able to somehow obtain its v8::Promise::Resolver in order to resolve it. We must not make use of the implementation fact that the v8::Promise is the v8::Promise::Resolver because V8 might later change on us.

Now, if we hide the v8::Promise::Resolver inside the v8::Promise using our napi_wrap() technique when we create the v8::Promise in napi_create_promise() then we give the appearance that one can resolve a v8::Promise - any v8::Promise - via napi_resolve_promise(). That's not true though, because internally we'd be retrieving the v8::Promise::Resoslver in order to perform the resolve/reject. Now, v8::Promise instances not created using napi_create_promise() would not have a v8::Promise::Resolver hidden inside them, and so we'd have to error out when the application attempted to resolve a promise not created with napi_create_promise(). This would be confusing to users.

Thus, If we are not to covey the impression that napi_create_promise() creates a promise which can then be passed to napi_resolve_promise() or napi_reject_promise() then we need to introduce the concept of a deferred in order to distinguish the promises we can resolve from those we cannot.

Contributor

gabrielschulhof commented Jul 19, 2017

@benjamingr the V8 implementation provides two objects: a resolver and a promise. Now, it's true that they are in reality one and the same object, but that's an implementation detail that the API does not document. The v8 API certainly suggests that, given a random v8::Promise we need the corresponding v8::Promise::Resolver to resolve it.

So, if somebody passes in a v8::Promise from the JS side, we must be able to somehow obtain its v8::Promise::Resolver in order to resolve it. We must not make use of the implementation fact that the v8::Promise is the v8::Promise::Resolver because V8 might later change on us.

Now, if we hide the v8::Promise::Resolver inside the v8::Promise using our napi_wrap() technique when we create the v8::Promise in napi_create_promise() then we give the appearance that one can resolve a v8::Promise - any v8::Promise - via napi_resolve_promise(). That's not true though, because internally we'd be retrieving the v8::Promise::Resoslver in order to perform the resolve/reject. Now, v8::Promise instances not created using napi_create_promise() would not have a v8::Promise::Resolver hidden inside them, and so we'd have to error out when the application attempted to resolve a promise not created with napi_create_promise(). This would be confusing to users.

Thus, If we are not to covey the impression that napi_create_promise() creates a promise which can then be passed to napi_resolve_promise() or napi_reject_promise() then we need to introduce the concept of a deferred in order to distinguish the promises we can resolve from those we cannot.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Jul 19, 2017

Contributor

@benjamingr another unpleasant side-effect of allowing one to resolve any promise natively is this:

addon.acceptPromise( new Promise( function( resolve, reject ) {
  ...
  resolve();
  ...
} ) );

and then

napi_value the_passed_in_promise;
...
napi_promise_resolve(env, the_passed_in_promise, the_result);

Now, the JS function responsible for resolving the promise is completely shoved aside. In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

Contributor

gabrielschulhof commented Jul 19, 2017

@benjamingr another unpleasant side-effect of allowing one to resolve any promise natively is this:

addon.acceptPromise( new Promise( function( resolve, reject ) {
  ...
  resolve();
  ...
} ) );

and then

napi_value the_passed_in_promise;
...
napi_promise_resolve(env, the_passed_in_promise, the_result);

Now, the JS function responsible for resolving the promise is completely shoved aside. In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

@benjamingr

This comment has been minimized.

Show comment
Hide comment
@benjamingr

benjamingr Jul 20, 2017

Member

So, if somebody passes in a v8::Promise from the JS side, we must be able to somehow obtain its v8::Promise::Resolver in order to resolve it.

Yes, we can keep a map of native promises and resolvers for unresolved promises - when a promise is resolved we remove it from the map.

Now, if we hide the v8::Promise::Resolver inside the v8::Promise using our napi_wrap() technique when we create the v8::Promise in napi_create_promise() then we give the appearance that one can resolve a v8::Promise - any v8::Promise - via napi_resolve_promise()

That's a good point, although we can return a ResolvablePromise or some type that gives us this capability.

In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

This is how promises work though. The first resolver wins - I'd assume someone writing that sort of code is using this as a feature and not running into it as a bug.

Member

benjamingr commented Jul 20, 2017

So, if somebody passes in a v8::Promise from the JS side, we must be able to somehow obtain its v8::Promise::Resolver in order to resolve it.

Yes, we can keep a map of native promises and resolvers for unresolved promises - when a promise is resolved we remove it from the map.

Now, if we hide the v8::Promise::Resolver inside the v8::Promise using our napi_wrap() technique when we create the v8::Promise in napi_create_promise() then we give the appearance that one can resolve a v8::Promise - any v8::Promise - via napi_resolve_promise()

That's a good point, although we can return a ResolvablePromise or some type that gives us this capability.

In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

This is how promises work though. The first resolver wins - I'd assume someone writing that sort of code is using this as a feature and not running into it as a bug.

@benjamingr

This comment has been minimized.

Show comment
Hide comment
@benjamingr

benjamingr Jul 20, 2017

Member

Thanks a lot for working on this by the way - I'm sorry I'm not familiar with all the previous discussion and intend to read it asap. I care about having a convenient n_api promise interface because I intend to use it a lot :)

Member

benjamingr commented Jul 20, 2017

Thanks a lot for working on this by the way - I'm sorry I'm not familiar with all the previous discussion and intend to read it asap. I care about having a convenient n_api promise interface because I intend to use it a lot :)

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Jul 20, 2017

Contributor

In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

This is how promises work though. The first resolver wins - I'd assume someone writing that sort of code is using this as a feature and not running into it as a bug.

Wait, what? Multiple resolvers? I mean, OK, Promise.race() behaves like that, but a single promise? My understanding is that given a promise, it can be resolved in exactly one place, namely inside its executor. In JS this is solved by making the resolve and reject callbacks arguments to the executor. I mean, you can leak the resolve and reject callbacks by having the executor assign them as properties on the promise object, but that's pretty ... I dunno ... hackish?

Now, on the native side we do not have the luxury of using scope to at least discourage people from passing around the resolve and reject callbacks (collected in the deferred in the N-API implementation), but we still have the same concept of a single resolver being associated with a promise.

That's why I believe it would be confusing if a user created a Promise in JS and found that its conclusion was not the result of having performed whatever was given in the executor.

Yes, we can keep a map of native promises and resolvers for unresolved promises - when a promise is resolved we remove it from the map.

We are already storing a lot of things in the napi_env, and if we add this map we expose promises to the issue currently facing napi_env which is that each module has its own napi_env, so one module couldn't resolve another module's promises because they wouldn't be in its map.

Also, users who pass a JS-created native promise into napi_resolve_promise() would continue to find it confusing that napi_resolve_promise() fails because internally the promise they passed does not map to any resolver because it wasn't created with napi_create_promise().

I guess the fundamental questions are: Do we value the abstraction imposed by JS wherein upon receiving a Promise object from somewhere, the receiver cannot resolve it, but can only wait for its conclusion? Do we value that the promise can only be resolved by its executor, unless the user jumps through some (to-be-frowned-upon?) hoops of assigning the resolve and reject to the Promise instance?

If so, then we should seek to encourage code that keeps native code from resolving JS promises, and keeps JS code from resolving native promises.

Contributor

gabrielschulhof commented Jul 20, 2017

In fact, we don't know whether the promise will be resolved by the native side or by the JS side - depends on which finishes first.

This is how promises work though. The first resolver wins - I'd assume someone writing that sort of code is using this as a feature and not running into it as a bug.

Wait, what? Multiple resolvers? I mean, OK, Promise.race() behaves like that, but a single promise? My understanding is that given a promise, it can be resolved in exactly one place, namely inside its executor. In JS this is solved by making the resolve and reject callbacks arguments to the executor. I mean, you can leak the resolve and reject callbacks by having the executor assign them as properties on the promise object, but that's pretty ... I dunno ... hackish?

Now, on the native side we do not have the luxury of using scope to at least discourage people from passing around the resolve and reject callbacks (collected in the deferred in the N-API implementation), but we still have the same concept of a single resolver being associated with a promise.

That's why I believe it would be confusing if a user created a Promise in JS and found that its conclusion was not the result of having performed whatever was given in the executor.

Yes, we can keep a map of native promises and resolvers for unresolved promises - when a promise is resolved we remove it from the map.

We are already storing a lot of things in the napi_env, and if we add this map we expose promises to the issue currently facing napi_env which is that each module has its own napi_env, so one module couldn't resolve another module's promises because they wouldn't be in its map.

Also, users who pass a JS-created native promise into napi_resolve_promise() would continue to find it confusing that napi_resolve_promise() fails because internally the promise they passed does not map to any resolver because it wasn't created with napi_create_promise().

I guess the fundamental questions are: Do we value the abstraction imposed by JS wherein upon receiving a Promise object from somewhere, the receiver cannot resolve it, but can only wait for its conclusion? Do we value that the promise can only be resolved by its executor, unless the user jumps through some (to-be-frowned-upon?) hoops of assigning the resolve and reject to the Promise instance?

If so, then we should seek to encourage code that keeps native code from resolving JS promises, and keeps JS code from resolving native promises.

@benjamingr

This comment has been minimized.

Show comment
Hide comment
@benjamingr

benjamingr Jul 20, 2017

Member

Wait, what? Multiple resolvers? I mean, OK, Promise.race() behaves like that, but a single promise? My understanding is that given a promise, it can be resolved in exactly one place, namely inside its executor. In JS this is solved by making the resolve and reject callbacks arguments to the executor

Making resolve/reject executor arguments was done for throw safety (so synchronous throws convert to rejections in the promise constructor).

new Promise((resolve, reject) => { // valid JS
  resolve(3);
  resolve(5); // noop
  reject(null); // also noop, only the first one counts
});

This is by design, and in fact how you'd implement race. I don't mind forbidding it in the n-api side but it would certainly not be the default and expected behavior for promise resolution.

I mean, you can leak the resolve and reject callbacks by having the executor assign them as properties on the promise object, but that's pretty ... I dunno ... hackish?

Let me clarify - the JS side should not be able to resolve the promise, what I'm suggesting is returning the promise object to the JS side (it can't resolve it) and resolving it only on the V8 side (since V8 can resolve on promise objects - or we can keep a mapping).

That's why I believe it would be confusing if a user created a Promise in JS and found that its conclusion was not the result of having performed whatever was given in the executor.

Simple - don't allow resolving promises that were created outside of n-api (or ones you don't have in the map).

so one module couldn't resolve another module's promises because they wouldn't be in its map.

That sounds like a pretty good idea to me regardless .- similarly to JS not resolving these promises. (I think?)

I guess the fundamental questions are: Do we value the abstraction imposed by JS wherein upon receiving a Promise object from somewhere, the receiver cannot resolve it, but can only wait for its conclusion?

I think we should.

Do we value that the promise can only be resolved by its executor, unless the user jumps through some (to-be-frowned-upon?) hoops of assigning the resolve and reject to the Promise instance?

These hooks were never frowned upon, the promise constructor was designed to run synchronously precisely so these use cases would be enabled. That said - I'm 100% for having JS users only resolve promises through the executor (and hopefully through util.promisify which resolves without an executor - but that's another story).


Basically, my main issue with this PR is that we have an extra type for a capability (which is something that is often done in OO) - but we're writing C so we don't really need that - since simply access to napi_resolve_promise would mean we're "priviledged" (and have the capability).

Your point about this meaning we're able to resolve promises we did not create is very good which is why I think the map is a good idea. That said, having a deferred is nice because it converts a would-be runtime error to a compile time error.

I'd like to think about having a nicer API for a day or two (we can also solve it with a resolvable-promise type - but I'm not sure that's better.

Member

benjamingr commented Jul 20, 2017

Wait, what? Multiple resolvers? I mean, OK, Promise.race() behaves like that, but a single promise? My understanding is that given a promise, it can be resolved in exactly one place, namely inside its executor. In JS this is solved by making the resolve and reject callbacks arguments to the executor

Making resolve/reject executor arguments was done for throw safety (so synchronous throws convert to rejections in the promise constructor).

new Promise((resolve, reject) => { // valid JS
  resolve(3);
  resolve(5); // noop
  reject(null); // also noop, only the first one counts
});

This is by design, and in fact how you'd implement race. I don't mind forbidding it in the n-api side but it would certainly not be the default and expected behavior for promise resolution.

I mean, you can leak the resolve and reject callbacks by having the executor assign them as properties on the promise object, but that's pretty ... I dunno ... hackish?

Let me clarify - the JS side should not be able to resolve the promise, what I'm suggesting is returning the promise object to the JS side (it can't resolve it) and resolving it only on the V8 side (since V8 can resolve on promise objects - or we can keep a mapping).

That's why I believe it would be confusing if a user created a Promise in JS and found that its conclusion was not the result of having performed whatever was given in the executor.

Simple - don't allow resolving promises that were created outside of n-api (or ones you don't have in the map).

so one module couldn't resolve another module's promises because they wouldn't be in its map.

That sounds like a pretty good idea to me regardless .- similarly to JS not resolving these promises. (I think?)

I guess the fundamental questions are: Do we value the abstraction imposed by JS wherein upon receiving a Promise object from somewhere, the receiver cannot resolve it, but can only wait for its conclusion?

I think we should.

Do we value that the promise can only be resolved by its executor, unless the user jumps through some (to-be-frowned-upon?) hoops of assigning the resolve and reject to the Promise instance?

These hooks were never frowned upon, the promise constructor was designed to run synchronously precisely so these use cases would be enabled. That said - I'm 100% for having JS users only resolve promises through the executor (and hopefully through util.promisify which resolves without an executor - but that's another story).


Basically, my main issue with this PR is that we have an extra type for a capability (which is something that is often done in OO) - but we're writing C so we don't really need that - since simply access to napi_resolve_promise would mean we're "priviledged" (and have the capability).

Your point about this meaning we're able to resolve promises we did not create is very good which is why I think the map is a good idea. That said, having a deferred is nice because it converts a would-be runtime error to a compile time error.

I'd like to think about having a nicer API for a day or two (we can also solve it with a resolvable-promise type - but I'm not sure that's better.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Jul 21, 2017

Contributor

@benjamingr

That said, having a deferred is nice because it converts a would-be runtime error to a compile time error.

Actually, it currently doesn't convert it to a compile time error because a deferred is currently simply a napi_value - although we could introduce a type for it which internally would store a persistent to the deferred, and would free it upon resolve/reject.

Contributor

gabrielschulhof commented Jul 21, 2017

@benjamingr

That said, having a deferred is nice because it converts a would-be runtime error to a compile time error.

Actually, it currently doesn't convert it to a compile time error because a deferred is currently simply a napi_value - although we could introduce a type for it which internally would store a persistent to the deferred, and would free it upon resolve/reject.

@addaleax

This comment has been minimized.

Show comment
Hide comment
@addaleax

addaleax Jul 30, 2017

Member

This would need to be rebased again, sorry.

Member

addaleax commented Jul 30, 2017

This would need to be rebased again, sorry.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 3, 2017

Contributor

@addaleax NP. Rebasing when I get a chance.

Contributor

gabrielschulhof commented Aug 3, 2017

@addaleax NP. Rebasing when I get a chance.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 4, 2017

Contributor

@benjamingr have you had a chance to think about a nicer API? Is it OK to proceed with this API?

Contributor

gabrielschulhof commented Aug 4, 2017

@benjamingr have you had a chance to think about a nicer API? Is it OK to proceed with this API?

@benjamingr

This comment has been minimized.

Show comment
Hide comment
@benjamingr

benjamingr Aug 5, 2017

Member

Oh sorry, I thought you were going to follow up with:

Actually, it currently doesn't convert it to a compile time error because a deferred is currently simply a napi_value - although we could introduce a type for it which internally would store a persistent to the deferred, and would free it upon resolve/reject.

I didn't realize you were waiting for me - if you'd like I can sit on the API this week.

Member

benjamingr commented Aug 5, 2017

Oh sorry, I thought you were going to follow up with:

Actually, it currently doesn't convert it to a compile time error because a deferred is currently simply a napi_value - although we could introduce a type for it which internally would store a persistent to the deferred, and would free it upon resolve/reject.

I didn't realize you were waiting for me - if you'd like I can sit on the API this week.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 5, 2017

Contributor

@benjamingr I guess I was thinking that I should have a look at the API you propose and then see if we need the persistent. Either way, in V8 the deferred can only be stored as something other than a napi_value if it is stored as a persistent, and then we need to have very clear semantics as to where it's created and where it's destroyed.

The reason for that was pointed out by @TimothyGu - namely that napi_value items are governed by scopes which can be declared so, if we have a second type that is also governed by scopes, we need to reproduce all the scope-related APIs for that type as well.

Please, if you find the time, think about the API, and I'll be happy to modify the PR!

Contributor

gabrielschulhof commented Aug 5, 2017

@benjamingr I guess I was thinking that I should have a look at the API you propose and then see if we need the persistent. Either way, in V8 the deferred can only be stored as something other than a napi_value if it is stored as a persistent, and then we need to have very clear semantics as to where it's created and where it's destroyed.

The reason for that was pointed out by @TimothyGu - namely that napi_value items are governed by scopes which can be declared so, if we have a second type that is also governed by scopes, we need to reproduce all the scope-related APIs for that type as well.

Please, if you find the time, think about the API, and I'll be happy to modify the PR!

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 17, 2017

Contributor

@benjamingr did you have a chance to think some more about the Promise N-API?

Contributor

gabrielschulhof commented Aug 17, 2017

@benjamingr did you have a chance to think some more about the Promise N-API?

@benjamingr

This comment has been minimized.

Show comment
Hide comment
@benjamingr

benjamingr Aug 18, 2017

Member

No sorry, going to lift my objection though. I'm more concerned with the capability than the API now - I think people might just end up wrapping it but exposing capabilities is more important

Member

benjamingr commented Aug 18, 2017

No sorry, going to lift my objection though. I'm more concerned with the capability than the API now - I think people might just end up wrapping it but exposing capabilities is more important

changed my mind

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 18, 2017

Contributor

@benjamingr Roger that! We can then proceed with the PR. Thanks for your thoughts! @TimothyGu @addaleax could you please have a look and/or ping somebody you know to be interested in/familiar with Promise?

Contributor

gabrielschulhof commented Aug 18, 2017

@benjamingr Roger that! We can then proceed with the PR. Thanks for your thoughts! @TimothyGu @addaleax could you please have a look and/or ping somebody you know to be interested in/familiar with Promise?

@addaleax

Basically LGTM

Show outdated Hide outdated src/node_api.cc
Show outdated Hide outdated src/node_api.cc
Show outdated Hide outdated src/node_api.cc
@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 19, 2017

Contributor

@addaleax there we go. resolve it is :)

Contributor

gabrielschulhof commented Aug 19, 2017

@addaleax there we go. resolve it is :)

@addaleax

This comment has been minimized.

Show comment
Hide comment
@addaleax

addaleax Aug 19, 2017

Member

Thanks!

Member

addaleax commented Aug 19, 2017

Thanks!

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 22, 2017

Contributor

@addaleax could you please have another look? I had to rebase after landing napi_remove_wrap() because both PRs touch the wrapping implementation.

Contributor

gabrielschulhof commented Aug 22, 2017

@addaleax could you please have another look? I had to rebase after landing napi_remove_wrap() because both PRs touch the wrapping implementation.

@addaleax

This comment has been minimized.

Show comment
Hide comment
@addaleax
Member

addaleax commented Aug 23, 2017

Show outdated Hide outdated doc/api/n-api.md
Show outdated Hide outdated doc/api/n-api.md
@jasnell

Documentation needs a bit more work

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Aug 24, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 24, 2017

Contributor

@addaleax here it is with napi_deferred.

@benjamingr I was able to render the deferred as a separate type with an explicit lifecycle bookended by napi_create_promise() and napi_resolve_deferred() or napi_reject_deferred(). Thus,

  • a N-API promise can be resolved/rejected exactly once, because the deferred which is allocated in napi_create_promise() is freed in napi_resolve_deferred() or napi_reject_deferred(). Thus,
    • Failing to resolve/reject a promise results in the leak of the deferred.
    • Attempting to resolve/reject a promise multiple times results in a double free of the deferred.
  • The code is indeed simpler to write as well as implement, because there is no more need to store a reference to the deferred in order to have it escape the handle scope, since the deferred is precisely such a reference.
Contributor

gabrielschulhof commented Aug 24, 2017

@addaleax here it is with napi_deferred.

@benjamingr I was able to render the deferred as a separate type with an explicit lifecycle bookended by napi_create_promise() and napi_resolve_deferred() or napi_reject_deferred(). Thus,

  • a N-API promise can be resolved/rejected exactly once, because the deferred which is allocated in napi_create_promise() is freed in napi_resolve_deferred() or napi_reject_deferred(). Thus,
    • Failing to resolve/reject a promise results in the leak of the deferred.
    • Attempting to resolve/reject a promise multiple times results in a double free of the deferred.
  • The code is indeed simpler to write as well as implement, because there is no more need to store a reference to the deferred in order to have it escape the handle scope, since the deferred is precisely such a reference.
@TimothyGu

Two last comments. Appreciating the puns in the test file :)

Show outdated Hide outdated src/node_api.cc
assert.strictEqual(test_promise.isPromise(2.4), false,
'Number is recognized as not a promise');
assert.strictEqual(test_promise.isPromise('I promise!'), false,

This comment has been minimized.

@TimothyGu

TimothyGu Aug 24, 2017

Member

Hah!

@TimothyGu

TimothyGu Aug 24, 2017

Member

Hah!

assert.strictEqual(result, expected_result,
'promise rejected as expected');
}));
test_promise.concludeCurrentPromise(expected_result, false);

This comment has been minimized.

@TimothyGu

TimothyGu Aug 24, 2017

Member

Would be nice to test resolution and rejection behavior with promises as @addaleax noted in #14365 (comment).

@TimothyGu

TimothyGu Aug 24, 2017

Member

Would be nice to test resolution and rejection behavior with promises as @addaleax noted in #14365 (comment).

@benjamingr

Got around to reading the code and running the example - looks good to me and the examples are very clear.

I will still likely wrap the API in my code - but n-api is about providing consistent capabilities and not about having the most beautiful API - so I think as a platform this is fine to ship.

Thanks for doing this and putting up with me changing my mind :)

@jasnell

I'm liking where this has ended up. Good work.

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 24, 2017

Contributor

@jasnell Thanks!

Contributor

gabrielschulhof commented Aug 24, 2017

@jasnell Thanks!

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Aug 24, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 24, 2017

Contributor

@TimothyGu I added that test.

Contributor

gabrielschulhof commented Aug 24, 2017

@TimothyGu I added that test.

@addaleax

Still LGTM

Show outdated Hide outdated src/node_api.cc
n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: #14365
@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof
Contributor

gabrielschulhof commented Aug 24, 2017

@addaleax Done.

@TimothyGu

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 25, 2017

Contributor

Addressing the failure of node-test-binary-arm: https://ci.nodejs.org/job/node-test-binary-arm/9844/

Contributor

gabrielschulhof commented Aug 25, 2017

Addressing the failure of node-test-binary-arm: https://ci.nodejs.org/job/node-test-binary-arm/9844/

@gabrielschulhof

This comment has been minimized.

Show comment
Hide comment
@gabrielschulhof

gabrielschulhof Aug 25, 2017

Contributor

Landed in 7efb8f7.

Contributor

gabrielschulhof commented Aug 25, 2017

Landed in 7efb8f7.

gabrielschulhof added a commit that referenced this pull request Aug 25, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: #14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

@gabrielschulhof gabrielschulhof deleted the gabrielschulhof:napi-promise branch Aug 25, 2017

addaleax added a commit to addaleax/ayo that referenced this pull request Aug 25, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs/node#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

addaleax added a commit to ayojs/ayo that referenced this pull request Aug 28, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs/node#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

MylesBorins added a commit that referenced this pull request Sep 10, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: #14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

@MylesBorins MylesBorins referenced this pull request Sep 10, 2017

Merged

v8.5.0 proposal #15308

MylesBorins added a commit that referenced this pull request Sep 12, 2017

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: #14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

MylesBorins added a commit that referenced this pull request Sep 12, 2017

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  #14875

* console:
  * Implement minimal `console.group()`.
  #14910

* deps:
  * upgrade libuv to 1.14.1
    #14866
  * update nghttp2 to v1.25.0
    #14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    #14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    #15034

* inspector:
  * Enable async stack traces
    #13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    #14369

* napi:
  * implement promise
    #14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    #14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    #14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

PR-URL: #15308

MylesBorins added a commit that referenced this pull request Sep 12, 2017

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  #14875

* console:
  * Implement minimal `console.group()`.
  #14910

* deps:
  * upgrade libuv to 1.14.1
    #14866
  * update nghttp2 to v1.25.0
    #14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    #14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    #15034

* inspector:
  * Enable async stack traces
    #13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    #14369

* napi:
  * implement promise
    #14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    #14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    #14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

PR-URL: #15308

MylesBorins added a commit that referenced this pull request Sep 12, 2017

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  #14875

* console:
  * Implement minimal `console.group()`.
  #14910

* deps:
  * upgrade libuv to 1.14.1
    #14866
  * update nghttp2 to v1.25.0
    #14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    #14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    #15034

* inspector:
  * Enable async stack traces
    #13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    #14369

* napi:
  * implement promise
    #14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    #14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    #14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

PR-URL: #15308

MylesBorins added a commit that referenced this pull request Sep 12, 2017

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  #14875

* console:
  * Implement minimal `console.group()`.
  #14910

* deps:
  * upgrade libuv to 1.14.1
    #14866
  * update nghttp2 to v1.25.0
    #14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    #14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    #15034

* inspector:
  * Enable async stack traces
    #13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    #14369

* napi:
  * implement promise
    #14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    #14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    #14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

PR-URL: #15308

addaleax added a commit to addaleax/node that referenced this pull request Sep 13, 2017

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  nodejs#14875

* console:
  * Implement minimal `console.group()`.
  nodejs#14910

* deps:
  * upgrade libuv to 1.14.1
    nodejs#14866
  * update nghttp2 to v1.25.0
    nodejs#14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    nodejs#14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    nodejs#15034

* inspector:
  * Enable async stack traces
    nodejs#13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    nodejs#14369

* napi:
  * implement promise
    nodejs#14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    nodejs#14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    nodejs#14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](nodejs#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

PR-URL: nodejs#15308

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Mar 12, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Mar 12, 2018

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  nodejs#14875

* console:
  * Implement minimal `console.group()`.
  nodejs#14910

* deps:
  * upgrade libuv to 1.14.1
    nodejs#14866
  * update nghttp2 to v1.25.0
    nodejs#14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    nodejs#14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    nodejs#15034

* inspector:
  * Enable async stack traces
    nodejs#13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    nodejs#14369

* napi:
  * implement promise
    nodejs#14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    nodejs#14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    nodejs#14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](nodejs#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

This applies parts of a10856a that are
relevant to N-API.

PR-URL: nodejs#15308

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Mar 15, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Mar 15, 2018

2017-09-12, Version 8.5.0 (Current)
Notable Changes

* build:
  * Snapshots are now re-enabled in V8
  nodejs#14875

* console:
  * Implement minimal `console.group()`.
  nodejs#14910

* deps:
  * upgrade libuv to 1.14.1
    nodejs#14866
  * update nghttp2 to v1.25.0
    nodejs#14955

* dns:
  * Add `verbatim` option to dns.lookup(). When true, results from the
    DNS resolver are passed on as-is, without the reshuffling that
    Node.js otherwise does that puts IPv4 addresses before IPv6
    addresses.
    nodejs#14731

* fs:
  * add fs.copyFile and fs.copyFileSync which allows for more efficient
    copying of files.
    nodejs#15034

* inspector:
  * Enable async stack traces
    nodejs#13870

* module:
  * Add support for ESM. This is currently behind the
    `--experimental-modules` flag and requires the .mjs extension.
    `node --experimental-modules index.mjs`
    nodejs#14369

* napi:
  * implement promise
    nodejs#14365

* os:
  * Add support for CIDR notation to the output of the
    networkInterfaces() method.
    nodejs#14307

* perf_hooks:
  * An initial implementation of the Performance Timing API for
    Node.js. This is the same Performance Timing API implemented by
    modern browsers with a number of Node.js specific properties. The
    User Timing mark() and measure() APIs are implemented, as is a
    Node.js specific flavor of the Frame Timing for measuring event
    loop duration.
    nodejs#14680

* tls:
  * multiple PFX in createSecureContext
    [#14793](nodejs#14793)

* Added new collaborators:
  * BridgeAR – Ruben Bridgewater

This applies parts of a10856a that are
relevant to N-API.

PR-URL: nodejs#15308

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Apr 3, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Apr 6, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

gabrielschulhof added a commit to gabrielschulhof/node that referenced this pull request Apr 10, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

PR-URL: nodejs#14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

MylesBorins added a commit that referenced this pull request Apr 16, 2018

n-api: implement promise
Promise is implemented as a pair of objects. `napi_create_promise()`
returns both a JavaScript promise and a newly allocated "deferred" in
its out-params. The deferred is linked to the promise such that the
deferred can be passed to `napi_resolve_deferred()` or
`napi_reject_deferred()` to reject/resolve the promise.

`napi_is_promise()` can be used to check if a `napi_value` is a native
promise - that is, a promise created by the underlying engine, rather
than a pure JS implementation of a promise.

Backport-PR-URL: #19447
PR-URL: #14365
Fixes: nodejs/abi-stable-node#242
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>

@MylesBorins MylesBorins referenced this pull request Apr 16, 2018

Merged

v6.14.2 proposal #19996

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment