Starting from Node.js v26.4.0 native modules are expected to call the micro tasks queue and process.nextTick handlers themselves if they do any async work.
Node.js exports a RAII guard, CallbackScope, that does automatically at the end of the functions that create it.
The module is supposed to be doing this on the main thread after the async work has been completed.
Or, alternatively, there is the makeCallback method which combines a CallbackScope with a Call method - it is a shorthand for calling into JavaScript and running the micro tasks.
It appears that this has been specified to work this way since Node.js v9.0.0 but until now Node.js would always process the handlers in all cases. Starting with Node.js v26.4.0, this is no longer the case.
I have first encountered the problem with NAN and I haven't reproduced it with node-addon-api, but I see that this fully applies to it too.
Note that Node.js still calls the micro tasks most of the time except in some cases, which makes debugging this problem rather unpleasant.
- The default
OnOK``AsyncWorker uses Call instead of makeCallback
- There is an
AsyncResource class but this class is not used at all by AsyncWorker - it is up to the module to create it
- This is also true when using the
Promise helpers - they do not call the micro tasks either
Unlike NAN, node-addon-api exports all necessary APIs, however it is currently somewhat misleading and definitely does not make it clear that this is something that is up to the module (especially since until Node.js v26.4.0 it was not).
I think that by default the AsyncWorker class should create an AsyncContext that must be accessible to derived classes (protected) and the OnOK/OnError methods should use makeCallback with this async context. When using a Promise - or when overriding OnOK/OnError, there should be a mention in the documentation that the module must use a CallbackScope.
Further info:
nodejs/nan#1024
nodejs/node#66158
Starting from Node.js v26.4.0 native modules are expected to call the micro tasks queue and
process.nextTickhandlers themselves if they do any async work.Node.js exports a RAII guard,
CallbackScope, that does automatically at the end of the functions that create it.The module is supposed to be doing this on the main thread after the async work has been completed.
Or, alternatively, there is the
makeCallbackmethod which combines aCallbackScopewith aCallmethod - it is a shorthand for calling into JavaScript and running the micro tasks.It appears that this has been specified to work this way since Node.js v9.0.0 but until now Node.js would always process the handlers in all cases. Starting with Node.js v26.4.0, this is no longer the case.
I have first encountered the problem with NAN and I haven't reproduced it with
node-addon-api, but I see that this fully applies to it too.Note that Node.js still calls the micro tasks most of the time except in some cases, which makes debugging this problem rather unpleasant.
OnOK``AsyncWorkerusesCallinstead ofmakeCallbackAsyncResourceclass but this class is not used at all byAsyncWorker- it is up to the module to create itPromisehelpers - they do not call the micro tasks eitherUnlike NAN,
node-addon-apiexports all necessary APIs, however it is currently somewhat misleading and definitely does not make it clear that this is something that is up to the module (especially since until Node.js v26.4.0 it was not).I think that by default the
AsyncWorkerclass should create anAsyncContextthat must be accessible to derived classes (protected) and theOnOK/OnErrormethods should usemakeCallbackwith this async context. When using aPromise- or when overridingOnOK/OnError, there should be a mention in the documentation that the module must use aCallbackScope.Further info:
nodejs/nan#1024
nodejs/node#66158