Javascript函数使用promises而不返回正确的值

时间:2016-02-01 00:18:16

标签: node.js postgresql knex.js

作为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方法应该返回一个真值,否则返回false。我已经构建了一个函数,它接受一组模式键或表的名称,并将它传递给.every方法。然后.every方法使用knex.schema.hasTable方法返回true或false。

我担心的是,通过该功能的许多不同配置,我无法让它返回正确的值。它不仅会返回一个不正确的值,这可能与.every有关,我相信它可以返回“truthey”值,但是在定义函数之后,我会在以后调用它时经常遇到“函数未定义”错误文件。以下是我的功能示例 - 我认为这也是我对退货,承诺和关闭如何协同工作的理解不足,但如果有人有洞察力,那将非常感激。

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.

2 个答案:

答案 0 :(得分:2)

由于两个原因,您的功能无法正常运行:

  1. 您没有在checkTable函数声明中返回,因此它将始终返回undefined。 你应该写:
  2. 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对象(一个对象,即使是空的,也总是真实的)。
    2. 您现在要做的是检查表格是否存在异步,我将向您展示如何:

      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) then checkTable点击npm install express-generator -g ,但我会将此作为练习。 有关承诺的更多信息,请检查:

答案 1 :(得分:0)

感谢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