【问题标题】:Mysterious unhandled promise warning from NodeJS [duplicate]来自NodeJS的神秘未处理承诺警告[重复]
【发布时间】:2019-11-05 06:56:09
【问题描述】:

当以下代码错误(ping() 拒绝其承诺)时,我会收到警告。 HTTP 函数似乎出错了。我猜ping() 本身一定发生了什么事,这在某种程度上避免了 try-catch。

有人可以启发我吗? (这是在几次尝试改变事情以使其正常工作之后。)

(async () => {
    try {
            let webTask, pingTask;

            try {
                    webTask = httpsGet(urls[0]);
            } catch (e) {
                    console.log(e);
            }

            try {
                    pingTask = ping('8.8.8.8');
            } catch (e) {
                    console.log(e);
            }

            try {
                    const webResult = await webTask;
                    console.log('HTTP result:', webResult);
            } catch (e) {
                    console.log(e);
            }

            try {
                    const pingResult = await pingTask;
                    console.log('Ping result:', pingResult);
            } catch (e) {
                    console.log(e);
            }
    } catch (e) {
            console.log('Error:', e);
    }
})();

错误是:

"main.js" 137 lines, 2945 characters
(node:58299) UnhandledPromiseRejectionWarning: #<Object>
(node:58299) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:58299) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

这是我定义 ping 函数的文件的前面部分:

const netping = require('net-ping');
const pingSession = netping.createSession({
    retries: 0,
    timeout: 10000
});

const ping = ip => {
    return new Promise((resolve, reject) => {
            let result = { ipAddress: ip, start: new Date(Date.now()), end: null, error: null, duration_ms: -1 };

            pingSession.pingHost(ip, (error, target) => {
                    result.end = new Date(Date.now());
                    result.duration_ms = result.end - result.start;
                    if (error) {
                            result.error = error;
console.log('rejecting promise');
                            reject(result);
                    } else {
                            resolve(result);
console.log('resolving promise');
                    }
            });
    });
};

NodeJS 11.13.0

【问题讨论】:

  • 当拒绝被记录时,它到底指向哪里?在拒绝之前是否记录了任何错误?
  • 我会尝试stackoverflow.com/a/46964348/1026 或进一步减少:是什么让您认为未处理的拒绝承诺是从ping() 返回的承诺?消息中没有任何地方这么说。
  • 使用--trace-warnings,它可能会显示更多信息。
  • 首先更改为const webResult = await httpsGet(urls[0]);const pingResult = await ping('8.8.8.8');,然后去掉中间的promise 变量和重复的try/catch es(实际上不需要)。可能是解释器没有意识到您在代码后面处理拒绝。
  • @jfriend00 这就是我最初发生这种情况时的样子。

标签: javascript node.js promise


【解决方案1】:

await 是 javascript 构造,它将对 promise 的拒绝转换为异常。 也就是说,await 是处理拒绝的构造。

当你写作时:

try {
    pingTask = ping('8.8.8.8');
} catch (e) {
    console.log(e);
}

那里没有await,因此没有任何东西可以将拒绝转换为异常,或者确实以任何方式处理拒绝。

如果您要在不等待的情况下拨打ping(),那么您需要更明确的拒绝处理。

编辑

这是一个最小的复制器:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const test = (ms, msg) => {
    return new Promise((resolve, reject) => {
        sleep(ms).then(reject(msg)).catch(console.log);
    });
};

(async () => {
    let task1;

    try {
        const ms = 50;
        task1 = test(ms, "hey");
        await sleep(ms * 2); // otherwise you don't get an error
        await task1;
    } catch (e) {
        console.log(e);
    }
})().then(console.log).catch(console.log);

(节点:12822)UnhandledPromiseRejectionWarning:嘿(节点:12822) UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这 错误源于在异步函数内部抛出 没有 catch 块,或拒绝未处理的承诺 使用 .catch()。 (拒绝 ID:1)(节点:12822)[DEP0018] DeprecationWarning:不推荐使用未处理的承诺拒绝。在 未来,未处理的承诺拒绝将终止 具有非零退出代码的 Node.js 进程。嘿未定义(节点:12822) PromiseRejectionHandledWarning: Promise 拒绝已处理 异步(拒绝 id:1)

Promise() 构造函数开始运行test(),在 50 毫秒后,promise 被拒绝,但 没有 将拒绝转换为异常。 如果我们移除 100 毫秒的睡眠,那么 await 在 50 毫秒的睡眠完成之前将其“将拒绝转换为异常”逻辑注册到承诺方式,因此当承诺在 await 被调用后约 49 毫秒被拒绝时,有一个处理程序可以将其转换为异常。

【讨论】:

  • 所以,pingTask 是一个承诺。那个任务没有错。然后,在后面的代码中,他们执行await pingTask 并且它被try/catch 包围,它具有完整的错误处理。我看不出你说的是什么问题。
  • @jfriend00 回答已编辑以详细说明该问题。
  • @root 最初我将所有内容都放在一个 try-catch 和单行 var x = await foo() 行中,那是我第一次收到警告的时候。我把它拆开,希望缩小造成它的原因。所以如果我理解你的解释,我仍然需要在pingTask 上调用.catch,然后抛出,以适应当前的try-catch,对吗?我试图做的是同时运行这两个任务;认为await 阻塞。这样做(如果可能的话)是直接使用承诺的唯一方法吗?编辑:或并行运行,但 AFAIK 并不容易。
  • @jfriend00 我认为问题在于,如果存在两个 Promise,一个 Promise 被拒绝,而另一个被 awaited,则会发生未处理的拒绝即使被拒绝的 Promise 稍后会在 try/catch 中获得 awaited。解释器不知道被拒绝的 Promise 将在稍后处理,因为它目前正在 awaiting 另一个。
  • @CertainPerformance - 这就是为什么在catch 保护承诺之前使用中间变量来持有承诺可能会导致问题。出于这个原因,我不会那样写代码。事实证明,OP 无论如何都希望将这些与整个串行并行运行 await 逻辑只是他们想要完成的错误工具。他们可能想使用Promise.allSettled(),以便在完成这两项操作时收到通知。
猜你喜欢
  • 2020-01-01
  • 2018-07-02
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
相关资源
最近更新 更多