如何发现永远无法解决的承诺?

时间:2019-11-01 12:16:08

标签: node.js

const main = async () => {
  const foo = new Promise(() => {});

  foo
    .catch((error) => {
      console.log('error', error);
    })
    .then((response) => {
      console.log('response', response);
    });
};

main();

假设上面的代码片段,其中foo是某些第三方代码返回的错误处理的Promise:我如何检测到foo永远不会被解决?

出于某种背景,我正在尝试在第三方软件包中解决此bug问题。

1 个答案:

答案 0 :(得分:2)

我认为这是最接近检测Promise是否能够解决的人。

const asyncHooks = require('async_hooks');

const timeoutIdlePromise = async (createPromise, maximumIdleTime) => {
  return new Promise(async (resolve, reject) => {
    let Timeout;

    const parentAsyncIds = [];

    const asyncHook = asyncHooks.createHook({
      init: (asyncId, type, triggerAsyncId) => {
        if (parentAsyncIds.includes(triggerAsyncId)) {
          if (Timeout) {
            Timeout.refresh();
          }

          if (!parentAsyncIds.includes(asyncId)) {
            parentAsyncIds.push(asyncId);
          }
        }
      },
    });

    Timeout = setTimeout(() => {
      reject(new Error('Idle promise timeout.'));

       asyncHook.disable();
    }, maximumIdleTime);

    asyncHook.enable();

    // Force new async execution context.
    await null;

    const executionAsyncId = asyncHooks.executionAsyncId();

    parentAsyncIds.push(executionAsyncId);

    try {
      const result = await createPromise();

      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      asyncHook.disable();
    }
  })
};

// Rejected with Idle promise timeout.
timeoutIdlePromise(() => {
  return new Promise((resolve) => {

  });
}, 1000);

// Resolved.
timeoutIdlePromise(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      setTimeout(() => {
        setTimeout(() => {
          resolve();
        }, 500);
      }, 500);
    }, 500);
  });
}, 1000);

async_hooks用于检查诺言是否正在创建任何异步事件(以及由诺言创建的异步事件本身是否会创建其他异步事件,等等),只要诺言中存在某些异步活动(例如事件监听器,网络活动,超时),它将继续挂起。如果maximumIdleTime中没有异步活动,则会引发错误。

我已将以上逻辑抽象到模块timeout-idle-promise中。

import {
  timeoutIdlePromise,
  TimeoutError,
} from 'timeout-idle-promise';

// Rejected with TimeoutError error.
timeoutIdlePromise(() => {
  return new Promise((resolve) => {

  });
}, 1000);

// Resolved.
timeoutIdlePromise(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      setTimeout(() => {
        setTimeout(() => {
          resolve();
        }, 500);
      }, 500);
    }, 500);
  });
}, 1000);