首页 > 解决方案 > 为什么我会收到“已使用未定义的参数调用承诺执行程序”警告?(Node.js)

问题描述

我正在尝试使用 Promises 在 Node.js (v12.20.1) 中创建一个流/惰性列表。我的基本想法是,Stream 可以简单地是一个 Promise,它解析为一个值和另一个 Stream。考虑到这一点,我想出了这个递归定义:

class Stream extends Promise {
    constructor(executor) {
        super((resolve, reject) =>
            executor(
                (value) =>
                    resolve({
                        head: value,
                        tail: new Stream(executor),
                    }),
                reject
            )
        );
    }

    map(f) {
        return this.then((cell) => {
            return {
                head: f(cell.head),
                tail: cell.tail.map(f),
            };
        });
    }
}

现在,这实际上完成了我所期望的所有操作,但只要解析了一个值,就会打印出一些警告消息。例如,使用事件发射器作为流的源:

 > const Stream = require('./stream')
undefined
 > const { EventEmitter } = require('events')
undefined
 > const emitter = new EventEmitter();
undefined
 > const stream = new Stream((yieldValue, reject) => emitter.once('foo', yieldValue));
undefined
 > stream.map(console.log);
Stream [Promise] { <pending> }
 > emitter.emit('foo', 1);
true
 > 1
(node:22271) UnhandledPromiseRejectionWarning: TypeError: Promise executor has already been invoked with non-undefined arguments
    at /wd/stream.js:4:13
    at new Promise (<anonymous>)
    at new Stream (/wd/stream.js:3:9)
    at /wd/stream.js:8:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:22271) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:22271) [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.
 > emitter.emit('foo', 2);
true
 > 2
(node:22271) UnhandledPromiseRejectionWarning: TypeError: Promise executor has already been invoked with non-undefined arguments
    at /wd/stream.js:4:13
    at new Promise (<anonymous>)
    at new Stream (/wd/stream.js:3:9)
    at /wd/stream.js:8:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:22271) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)

我真的不明白这里出了什么问题。我不明白多次调用 executor 的问题是什么,因为它只是一个函数,而且我当然不知道导致第二次警告的原因,因为据我所知,这里没有任何 Promise 被拒绝?

提前感谢您的帮助!

标签: javascriptnode.jspromise

解决方案


问题是根据您子类this.then()化的构造函数的合同构造一个新的承诺。Promise为此,它使用一个执行程序调用您的Stream构造函数,该执行程序将使用传递的解析器函数通过then回调的结果解析新的 Promise。该执行程序预计只会被回调一次 - 但是您Stream确实会多次调用它,一次立即调用,然后在调用期间resolve调用。

在您的电话构建的各种承诺stream.map(console.log);中,从未在任何地方处理过,有些似乎被拒绝了——如果你问我,这是正确的。

Stream 可能递归链接的 Promise 1组成,但 Stream不是a Promise。不要使用子类化!

1: 见这个那个(也在这里)的例子。请注意,这个类似链表的概念已经被异步迭代器博客文章)所取代,它现在有一个有状态的next()方法。您还想看看异步生成器和 Observables 之间的区别是什么?.


推荐阅读