蓝鸟承诺变量:'undefined is not a function'

Bluebird promise variable: 'undefined is not a function'

我有一个 nodejs express 服务器,我正在使用 bluebird Promises 来同步所有异步内容。

使用 AWS RDS MySQL 数据库在本地主机上一切正常,但是当我将服务器上传到我的 AWS EC2 实例时,我发现此功能有问题:

var Promise = require('bluebird');
var db      = require('./db');

exports.matchValue = function (params) {
    return new Promise(function(resolve, reject) {
        var findValue = new Promise(); 
        if (params.find.includes(".")) {
            var aux = params.find.split(".");
            var matchBy = {};
            if (aux[0]) matchBy.a = aux[0];
            if (aux[1]) matchBy.b = aux[1];
            findValue = db.getValues1(params.limit,params.page,matchBy);
        }
        else {
            findValue = db.getValues2(params.limit,params.page,params.find);
        }
        findValue
        .then(function(result) {
            resolve(result);
        })
        .catch(function(err) {
            reject(err);
        });
    }); 
}

我已将变量 findValue 声明为新的 Promise,因为根据 if 条件,它将接收不同数据库查询函数的值(此函数 return 一个承诺)。

当我调用这个函数时,结果是这样的:"undefined is not a function".

我知道发生这种行为是因为它比 if/else 块代码先 findValue.then() 执行,并且由于变量未定义,它可以是一个函数。

我以为将一个变量声明为一个新的 Promise 它会等到分配给这个变量的函数的 return 完成,但实际上并没有发生。

我做错了什么?有人能帮我吗?

谢谢指教!!

I have declared the variable findValue as a new Promise because depending of the if condition, it will receive the value of a different database query function (this functions return a Promise).

在 JavaScript 中,您没有将变量声明为任何类型。这一行:

var findValue = new Promise();

声明一个变量 (var findValue) 并尝试创建一个承诺 (= new Promise())。 Promise 构造函数 要求 向它传递一个函数。它尝试将它的第一个参数用作函数,并且由于您没有向它传递任何参数,它得到第一个参数的 undefined - 因此是错误。

可以把它改成

var findValue;

...但是您的代码正在成为不必要的承诺创建谬误的牺牲品:只需使用您已经拥有的承诺:

exports.matchValue = function (params) {
    var findValue;
    if (params.find.includes(".")) {
        var aux = params.find.split(".");
        var matchBy = {};
        if (aux[0]) matchBy.a = aux[0];
        if (aux[1]) matchBy.b = aux[1];
        findValue = db.getValues1(params.limit,params.page,matchBy);
    }
    else {
        findValue = db.getValues2(params.limit,params.page,params.find);
    }
    return findValue;
}

您的 .matchValue() 函数应简化为:

exports.matchValue = function(params) {
    var aux = params.find.split('.');
    return (aux.length < 2) ? db.getValues2(params.limit, params.page, params.find) : db.getValues1(params.limit, params.page, { 'a': aux[0], 'b': aux[1] });
};

有了这个,.then(function(result) 肯定不会抛出,因为那一行已经消失了,但是函数的调用者可能会抛出。如果是这样,那么您必须(再次)怀疑 db.getValues1()db.getValues2() 没有 return EC2 服务器上的承诺;尝试记录 returned value/object 以查看它是什么。

假设您的 db.getValues1/db.getValues2 函数 return 承诺(它们似乎没有回调,我拒绝假设您在生产中使用同步数据库驱动程序), 请尝试以下版本的 posted 代码:

var Promise = require('bluebird');
var db      = require('./db');

exports.matchValue = function (params) {
    var findValue;

    if (params.find.includes(".")) {
        var aux = params.find.split(".");
        var matchBy = {};
        if (aux[0]) matchBy.a = aux[0];
        if (aux[1]) matchBy.b = aux[1];
        findValue = db.getValues1(params.limit,params.page,matchBy);
    }
    else {
        findValue = db.getValues2(params.limit,params.page,params.find);
    }

    return findValue;
}

如果有效,那就太好了。以下是一些需要考虑的事项:

  1. 您正在创建一个新的 Promise。不要那样做。使用 Bluebird 的 promisification 例程 Promisify 标准,符合节点 functions/libraries。

  2. Bluebird 2.x 和 3.x 将抛出 var findValue = new Promise()。正如已经指出的那样,构造函数需要一个函数作为它的参数。我怀疑您解释了您实际收到的错误消息。如果是这样,请不要那样做,这会让其他人很难找出问题所在。

  3. 下次您 post 进行 SO 时,请将您的示例代码缩减为任何人都可以 运行 并随时重现您的问题。您可能会发现在获得最小重现的过程中您解决了自己的问题。如果你不这样做,它会让这里的人更有效地帮助你。

我遇到了类似的问题,巧合的是我也在使用Sequelize。

这里有一个 one-liner 来重现问题:

Promise.resolve({ a: 1 }).then(([x]) => {});

输出:

Unhandled rejection TypeError: undefined is not a function

此错误的原因是 JavaScript 正在尝试对已解析的值执行 [Symbol.iterator](),但由于它是一个对象,因此它没有 [Symbol.iterator] - undefined在错误信息中是value[Symbol.iterator].

更好的错误消息应该是 value is not iterable.

行中的内容

至于你为什么会这样,那一定是Sequelize的bug。如果您仍然遇到问题,请提出问题。