deasync icon indicating copy to clipboard operation
deasync copied to clipboard

(Warning) Turning a Promise Sync, async hoot stack has become corrupted

Open folkvir opened this issue 8 years ago • 5 comments

When turning a Promise into a synchronous Promise Facing the following error: async hook stack has become corrupted

Error: async hook stack has become corrupted (actual: 6, expected: 7)
 1: v8::SnapshotCreator::`default constructor closure'
 2: node::CallbackScope::~CallbackScope
 3: node::CallbackScope::~CallbackScope
 4: RAND_query_egd_bytes
 5: RAND_query_egd_bytes
 6: uv_timer_get_repeat
 7: uv_run
 8: 00007FFB97441281
 9: 00007FFB974410B6
10: v8::internal::wasm::SignatureMap::Find
11: v8::internal::Builtins::CallableFor
12: v8::internal::Builtins::CallableFor
13: v8::internal::Builtins::CallableFor
14: 000001B9D57043C1

It occures when an error occured during the execution of the Promise. I can reproduce the error:

function waitPromise(val, time) {
  let result = undefined;
  new Promise(res => {
    setTimeout(() => {
      throw new Error('whatever');
      res(val);
    }, time);
  }).then(r => {
    result = r;
  });
  while(!result) {
    require('deasync').runLoopOnce();
  }
  return result;
}

console.log(waitPromise('my name is Bond, JAMES BOND!', 2000));

Make sure that in your Promise you do not have any error at all or the error will occur. Solve it by catching all error in the promise and returning the error as the result.

function waitPromise(val, time) {
  let result = undefined;
  new Promise((res, rej) => {
    setTimeout(() => {
      try {
        throw new Error('whatever');
        res(val);  
      } catch (error) {
        rej(error);
      }
    }, time);
  }).then(r => {
    result = r;
  }).catch(e => {
    result = e;
  });
  while(!result) {
    require('deasync').runLoopOnce();
  }
  return result;
}
console.log(waitPromise('my name is Bond, JAMES BOND!', 2000));

The same error occurs when using deasync-promise.

folkvir avatar Jan 07 '18 17:01 folkvir

Following up on this: is there any workaround for this issue to allow the setTimeout to correctly trigger without causing this exception?

emiliavanderwerf avatar May 07 '20 03:05 emiliavanderwerf

As I said:

Solve it by catching all errors in the promise and returning the error as the result.

Instead of rejecting, resolve the error with the object. And process the error outside of the deasync code.

folkvir avatar May 07 '20 11:05 folkvir

What about something like this?

const promiseSync = deasync((promise, cb) => {
  promise.then((result) => cb(null, result)).catch((error) => cb(error));
});

Or does that make the same error?

I'm using it in my .eslintrc.cjs like this:

const deasync = require('deasync'); // powerful magic

const promiseSync = deasync((promise, cb) => {
  promise.then((result) => cb(null, result)).catch((error) => cb(error));
});

const importSync = (name) => promiseSync(import(name));

// Look, no await needed here!
const something = importSync('./something.js').default;

module.exports = {
  ...something,
  // ...
}

trusktr avatar Nov 06 '20 08:11 trusktr

How about deasync(util.callbackify(promise => promise))?

SnirBroshi avatar Nov 15 '20 21:11 SnirBroshi

@NotWearingPants Neat. I didn't know about callbackify. Then my example would become:

const util = require('util')
const deasync = require('deasync')
const promiseSync = deasync(util.callbackify(promise => promise))
const importSync = specifier => promiseSync(import(specifier))

// Look, no await needed here!
const something = importSync('./something.js').default;

module.exports = {
  ...something,
  // ...
}

trusktr avatar Feb 06 '21 22:02 trusktr