简体   繁体   中英

Problem between async_hooks and promises on nodejs

I try to use the experimental module async_hooks in nodejs.

const Async = require('async_hooks');

const store = {};
const hook = Async.createHook({
    init: function (child, _, parent) {
        if (store[parent]) {
            store[child] = store[parent];
        }
    },
    destroy: function (id) {
        delete store[id];
    },
});
hook.enable();

let autoInc = 0;
let promise;
function run(index) {
    const asyncId = Async.executionAsyncId();
    if (!store[asyncId]) {
        store[asyncId] = { uuid: autoInc++ };
        console.log('ASYNC Created', store[asyncId]);
    } else {
        console.log('ASYNC Reuse', store[asyncId]);
    }
    
    if (!promise) {
        promise = Promise.resolve();
    }
    if (index < 1) {
        setTimeout(() => run(index+1), 0); // -> Version A
        // promise.then(() => run(index+1)); // -> Version B
    }
}

setTimeout(() => run(0), 0);
setTimeout(() => run(0), 0);

If i try 'Version A' (with setTimout) i've this output:

ASYNC Created { uuid: 0 }
ASYNC Created { uuid: 1 }
ASYNC Reuse { uuid: 0 }
ASYNC Reuse { uuid: 1 }

But if i try 'Version B' (with promises) i've this output:

ASYNC Created { uuid: 0 }
ASYNC Reuse { uuid: 0 }
ASYNC Created { uuid: 1 }
ASYNC Reuse { uuid: 0 }

The second execution context is attached to the first because the "then" is rattached on a promise of the first context. But it's very problematic: I cannot use it like a "ThreadLocal" in java. Do you have a solution? I can create a second promise to resolve the problem but it's not an acceptable solution for me.

Regards.

Thanks to @Robert Kawecki for library cls-hooked. I don't understand why but this library works better than async_hook method:

const CLS = require('cls-hooked');

const namespace = CLS.createNamespace('try-it');

let autoInc = 0;
let promise;
let allStores = [];
function run(index) {
    namespace.run(() => {
        const currentValue = namespace.get('id-context');
        if (currentValue === undefined) {
            namespace.set('id-context', autoInc++)
            console.log('namespace Created', namespace.get('id-context'));
        } else {
            console.log('namespace Reuse', namespace.get('id-context'));
        }

        if (!promise) {
            promise = Promise.resolve();
        }
        if (index < 1) {
            // setTimeout(() => run(index + 1), 0); // -> Version A
            // promise.then(() => run(index + 1)); // -> Version B
            setTimeout(() => {
                promise.then(() => run(index + 1));
            }, 10) // -> Version C
        }
    });
}

setTimeout(() => run(0), 0);
setTimeout(() => run(0), 0);

Versions A and C says

namespace Created 0
namespace Created 1
namespace Reuse 0
namespace Reuse 1

And version B says:

namespace Created 0
namespace Reuse 0
namespace Created 1
namespace Reuse 1

So i think that with this library Promises are rewrited to resolve the problem, but thanks for the solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM