【问题标题】:Promise resolves before forEach loop completesPromise 在 forEach 循环完成之前解决
【发布时间】:2018-04-28 03:50:57
【问题描述】:

我正在构建我的第一个 CRUD(库)应用程序,并且最近了解了将 Promise 作为一种避免深度嵌套回调的方法。每次服务器启动时,我都试图用一些数据为我的数据库播种,但我似乎在概念上遗漏了一些东西。

我在 bookData 数组中有四个对象,我想使用 Mongoose 对其进行迭代并保存到数据库:

function seedBooks() {
    return new Promise(function(resolve,reject){
        bookData.forEach(function(seed){
            Book.create(seed, function(err, newBook){
                if(err) {
                    reject(err);
                }
            });
        });
        resolve();
    });
}

这个函数是我试图链接在一起的几个函数之一,这就是我使用 Promise 的原因。但我发现seedBooks() 可以解决 1 到 4 个样本书的创建问题,

function seedDB() {
    removeAllBooks()
    .then(function(){
        return removeAllUsers();
    })
    .then(function(){
        return seedUsers();
    })
    .then(function(){
        return seedBooks();
    })
    .then(function(){
        return seedBookInstances();
    });
}

我是否理解或使用了 promise & resolve 不正确?任何帮助表示赞赏。谢谢!

【问题讨论】:

    标签: javascript mongoose promise es6-promise


    【解决方案1】:

    您正在同步解决您的 Promise,就在您启动您的 forEached 请求之后,这些请求是异步的。您可以尝试以下方法:

    function seedBooks() {
        return new Promise(function(resolve,reject){
            var count = 0, length = bookData.length;
            bookData.forEach(function(seed){
                Book.create(seed, function(err, newBook){
                    if(err) {
                        reject(err);
                        return;
                    }
                    if(count++ >= length ) {
                      resolve();
                    }
                });
            });
        });
    }
    

    这里的 Promise 只有在所有异步请求都完成后才会被解析。

    另一种选择是使用Promise.all。在这种方法中,您需要在循环中承诺所有请求,返回一个 Promises 数组,然后调用 Promise.all(_seedBooks()).then(),其中 _seedBook 返回一个 Promises 数组:

    function _seedBooks() {
        return bookData.map(function(seed) {
            return new Promise(function(resolve, reject) {
                Book.create(seed, function(err, newBook) {
                    if(err) {
                        reject(err);
                        return;
                    }
                    resolve(newBook);
                });
            });
        });
    }
    
    Promise.all(_seedBooks())
    .then(function(result) { /* result is the array of newBook objects */ })
    .catch(function(error) { /* error is the first rejected err */ })
    

    【讨论】:

      【解决方案2】:

      编辑: 下面解释了为什么您的代码无法正常工作,并就如何将 non-promise 代码转换为 Promise 提供一般建议。但是,由于 Mongoose 会产生 Promise,因此您应该使用它们而不是使用 new Promise。请参阅Olegzandr's answer


      承诺会立即解决,因为您正在立即调用resolve()

      将非承诺转换为承诺时的经验法则是承诺非承诺代码的最小部分。在这种情况下,这意味着承诺代码以保存单个项目。如果你这样做,呼叫resolve() 的收集地点就会变得清晰:

      function seedBook(seed) {
          return new Promise(function (resolve, reject) {
              Book.create(seed, function (err, newBook) {
                  if (err) { reject(err); } else { resolve(newBook); }
              });
          });
      }
      
      function seedBooks() {
          return Promise.all(bookData.map(seedBook));
      }
      

      如果您愿意,这还有一个好处是允许您访问返回的newBooks。

      【讨论】:

        【解决方案3】:

        如果您使用的是 Mongoose,您可以这样做:

        const saveBooks = function(books) {
            return books.map(function(seed) {
                    return Book.create(seed);  // returns a promise
                });
            });
        }
        
        return Promise.all(saveBooks(books)).then(function(){
            // all books are saved
        });
        

        【讨论】:

          猜你喜欢
          • 2018-07-07
          • 2020-02-19
          • 1970-01-01
          • 1970-01-01
          • 2018-03-22
          • 2019-03-31
          • 1970-01-01
          • 2017-05-30
          • 1970-01-01
          相关资源
          最近更新 更多