1

I'm learning how to use node-addon-api and now I'm stuck on async/await management. I cannot understand how to handle the case where a native function receive an object which has an async function.

Javascript:

const addon = require('bindings')('addon');

class Foo {
    async doAsync() {
        ...
    }
}

const useFoo = () => {
    const foo = new Foo();
    await addon.doStuff(foo);
}

Native:

#include <napi.h>
using namespace Napi;

Napi::Object doStuff(const Napi::CallbackInfo& info) {
     Napi::Env env = info.Env();
     MyObject* foo = Napi::ObjectWrap<MyObject>::Unwrap(info[0].As<Napi::Object>());
     // How should I await for this?
     foo.doAsync();
     ...
}

Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
    exports.Set(Napi::String::New(env, "doStuff"), Napi::Function::New(env, doStuff));
    return exports;
}

NODE_API_MODULE(addon, InitAll)

My problem is that I do not find any documentation about this behavior. I read about how to create a promise in native but not how to use it when received from JS.

Marco Stramezzi
  • 2,143
  • 4
  • 17
  • 37
  • What do you want to do with the promise? Probably you'll want to call its `then` method, there's not much else. (And no, I doubt there's an `await` counterpart in C++) – Bergi Jul 07 '19 at 12:33
  • Yes, I would use a JS class which has async methods in native code. I do not understand how this kind of object should be wrapped. – Marco Stramezzi Jul 08 '19 at 06:33
  • You wouldn't wrap it differently than a normal method returning a promise. – Bergi Jul 08 '19 at 09:49
  • There will be async/await in C++ 20, called coroutine, and you can use it as an experimental feature of many compilers. Then, create your own awaitable wrapper around Promise. – fjch1997 Dec 11 '19 at 20:18
  • To await something is equally to poll for a flag or to use a callback - in the Main thread it means to pause the execution - thus you'd wrap this in a std::thread or similar and return a deferred:: promise() - but now I wonder what information is so critical that it has to be called in native and cannot be awaited in js before ? – Estradiaz Feb 26 '20 at 07:40

1 Answers1

1

On the C++ addon side, you have to implement functionality asynchronously and return a Promise. See the link below for an example of exactly that.

On the Javascript side, you have to wrap that async/Promise call in an explicitly async Javascript function. Otherwise, if you try to await a Promise, you'll get an error about the function not being asynchronous. So on your JS side, something like the following should work:

async function init() {
  let obj = new YourAddon()
  let cnxnResult = await obj.connect()
}
init()

So you could create your own Javascript class (like your code examples) to wrap this C++ functionality and keep everything async/await friendly.

I found this link to be particularly helpful for showing how the C++ addon side is architected: Promise / AsyncWorker example