【问题标题】:Bluebird promise variable: 'undefined is not a function'蓝鸟承诺变量:'未定义不是函数'
【发布时间】:2016-07-23 14:51:05
【问题描述】:

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

使用 AWS RDS MySQL 数据库在 localhost 上一切正常,但是当我将服务器上传到我的 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 条件,它将接收不同数据库查询函数的值(此函数返回一个 Promise)。

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

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

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

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

谢谢你的建议!!

【问题讨论】:

  • 在哪里,你得到错误了吗?
  • 什么是params.find?因为您使用的是 params.find.includes,如果 params.find 是一个数组,那么它相对较新,并且不会存在于较旧的 JavaScript 引擎上。
  • 我在.then(function(result) 上收到错误,它仅在节点在 EC2 实例上运行时发生,当它在本地主机上运行时,结果包含查询响应,而 params.find 只是一个字符串.谢谢。
  • 这很奇怪。这表明您从getValues1(或getValues2)得到的并不是EC2 的承诺。
  • 您确定您需要的所有库都已正确安装在您的 EC2 实例上吗?

标签: javascript node.js promise bluebird


【解决方案1】:

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

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

var findValue = new Promise();

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

可以把它改成

var findValue;

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

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;
}

【讨论】:

  • 感谢您的回答 T.J.克劳德,但这是我测试的第一件事,也不起作用!它返回相同的消息
  • @javing:那么你需要澄清这个问题。具体来说,您从哪一行得到错误?
  • 看起来他的db 没有被承诺,而findValue 只是变成了undefined
  • @Bergi:如果 findValueundefined,我预计会出现不同的错误 (Cannot read property 'then' of undefined)。
  • 嗨 @Bergi 和 T.J.克劳德,我知道这已经很老了,但我发现了这里真正发生的事情,我想你们两个可能有兴趣阅读我的答案。我想知道你们中是否有人知道为什么 Bluebird 会给出这个疯狂的错误信息。谢谢!
【解决方案2】:

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

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 标准的、符合节点的函数/库。

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

  3. 下次您发布到 SO 时,请将您的示例代码缩减为任何人都可以运行并轻松重现您的问题的代码。您可能会发现在解决您自己的问题的最小复制过程中。如果您不这样做,这将使这里的人们能够更有效地帮助您。

【讨论】:

    【解决方案3】:

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

    这里是重现问题的单行代码:

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

    输出:

    未处理的拒绝类型错误:未定义不是函数

    这个错误的原因是 JavaScript 试图在解析的值上执行 [Symbol.iterator](),但由于它是一个对象,它没有 [Symbol.iterator] - 错误消息中的 undefinedvalue[Symbol.iterator] .

    更好的错误信息应该是 value is not iterable 行中的内容。

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

    【讨论】:

    • 这不是蓝鸟给出的错误,它是 js 引擎。尝试通过调用其[Symbol.iterator]() 方法来迭代值,如果那是undefined,则您得到的默认错误是您正在调用不存在的东西。看起来您的 node.js 版本在参数解构中没有更好的消息。
    • @Bergi 哎呀,你是对的。我将编辑答案。
    • 这与问题无关。是的,您收到了类似的错误消息,但有很多方法可以获取“undefined 不是函数”。这与问题中的不同,因为new Promise()(例如,没有参数)(正如我在回答中指出的那样)。你的问题是你试图在不可迭代的对象上使用可迭代的解构。 Promise.resolve({a: 1}).then(([x]) => {}); 尝试将可迭代解构 [x] 应用于 {a: 1},就好像你已经这样做了:const [x] = {a: 1};。它与承诺无关。
    【解决方案4】:

    您的 .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() 没有在 EC2 服务器上返回承诺;尝试记录返回的值/对象以查看它是什么。

    【讨论】:

    • 我已经删除了 if/else,并执行了与您的答案类似的操作(将 db 函数的结果返回给 findValue 并使用 findValue.then(result)),它工作正常,谢谢!跨度>
    • 很酷,但问题是什么以及究竟是什么解决了它是个谜。
    猜你喜欢
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 2014-11-06
    • 2015-09-06
    • 2015-02-13
    相关资源
    最近更新 更多