【问题标题】:Javascript function using promises and not returning the correct valueJavascript函数使用promise并且不返回正确的值
【发布时间】:2016-02-01 00:18:15
【问题描述】:

作为 Javascript 开发的相对起步者,我试图了解我在构建的函数中遇到的这个问题,该函数将成为连接到 postgreSQL 数据库的代码的一部分。

在这个函数中,我使用 knex 查询构建器方法来检查远程数据库中是否存在表,该方法解析为一个布尔值,指示您指定的字符串是否与中的同名表匹配数据库。我提供了一个 knex 语法的示例示例,以便人们更好地理解该函数。

knex.schema.hasTable('users').then(function(exists) {
  if (!exists) {
    return knex.schema.createTable('users', function(t) {
      t.increments('id').primary();
      t.string('first_name', 100);
      t.string('last_name', 100);
      t.text('bio');
    });
  }
});

我试图通过使用 .every Array 方法使我的函数返回一个布尔值,该方法检查每个数组并且如果每个索引都通过定义的条件,.every 方法应该返回一个真值,否则返回假。我已经构建了一个函数,它接受一组模式键或表名,并将其传递给 .every 方法。 .every 方法然后使用 knex.schema.hasTable 方法返回 true 或 false。

我担心的是,通过函数的许多不同配置,我无法让它返回正确的值。它不仅返回一个不正确的值,这可能与.every有关,我相信它可以返回“真实”的值,但是在定义函数之后,我经常会在稍后调用它时得到一个“函数未定义”的错误文件。这是我的函数示例 - 我再次认为这是我对返回、承诺和闭包如何协同工作的理解不足,但如果有人有见识,将不胜感激。

var schemaTables = ['posts','users', 'misc'];

// should return Boolean
function checkTable() {
    schemaTables.every(function(key) {
    return dbInstance.schema.hasTable(key)
        .then(function(exists) {
            return exists;
            });
    });
}

console.log(checkTable(), 'checkTable function outside');
// console.log is returning undefined here, although in other situations,
   I've seen it return true or false incorrectly.

【问题讨论】:

  • .every() 评估同步结果并使用同步回调,它不知道如何处理结果为异步承诺的回调。基本上,你不能在这里使用.every()

标签: node.js postgresql knex.js


【解决方案1】:

您的功能无法正常工作有两个原因:

  1. 你没有在checkTable 函数声明中返回,所以它总是返回未定义的。 你应该写:
function checkTable() {
  return schemaTables.every(function(key) {
    return dbInstance.schema.hasTable(key)
      .then(function(exists) {
        return exists;
      });
  });
}

无论如何你不会得到你想要的只是增加回报。我将在第二点解释原因。

  1. Array.prototype.every 期待一个真值或假值同步,但 dbInstance.schema.hasTable 返回的是一个 Promise 对象(并且一个对象,即使为空,也始终是真值)。

你现在要做的是检查表是否存在异步,我会告诉你如何:

var Promise = require("bluebird");
var schemaTables = ['posts', 'users', 'misc'];

function checkTable(tables, callback) {

  // I'm mapping every table into a Promise
  asyncTables = tables.map(function(table) {
    return dbInstance.schema.hasTable(table)
      .then(function(exists) {
        if (!exists)
          return Promise.reject("The table does not exists");
        return Promise.resolve("The table exists");
      });
  });

 // If all the tables exist, Promise.all return a promise that is fulfilled 
 // when all the items in the array are fulfilled.
 // If any promise in the array rejects, the returned promise 
 // is rejected with the rejection reason.
  Promise.all(asyncTables)
    .then(function(result) {
      // i pass a TRUE value to the callback if all the tables exist, 
      // if not i'm passing FALSE
      callback(result.isFulfilled());
    });

}


checkTable(schemaTables, function (result) {
  // here result will be true or false, you can do whatever you want
  // inside the callback with result, but it will be called ASYNCHRONOUSLY
  console.log(result);
});

请注意,正如我之前所说,您不能有一个同步返回 true 或 false 值的函数,因此您唯一能做的就是将回调传递给checkTable,该回调将在结果为准备好(当所有的承诺都实现或其中一个被拒绝时)。 或者你可以return Promise.all(asyncTables) 并在checkTable 上调用then 自己,但我会把这个留给你作为练习。 有关承诺检查的更多信息:

【讨论】:

    【解决方案2】:

    感谢 Cluk3 提供了非常全面的答案。我实际上通过使用异步库中的 .every 方法自己解决了这个问题。但是,是的,这主要是由于我对返回和异步与同步的误解。

    var checkTablesExist = function () {
        // make sure that all tables exist
        function checkTable(key, done) {
        dbInstance.schema.hasTable(key)
            .then(function(exists) {
                return done(exists);
                });
            }
    
        async.every(schemaTables, checkTable, 
            function(result) {
                return result;
            });
    };
    
    console.log(checkTablesExist());
    // will now print true or false correctly
    

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 2022-11-29
      • 2013-01-16
      • 2019-09-28
      • 2019-07-02
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 2017-08-09
      相关资源
      最近更新 更多