在forEach循环完成之前,Promise会解析

时间:2017-11-15 03:00:28

标签: javascript mongoose promise es6-promise

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

我在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();
    });
}

这个函数是我尝试连接在一起的少数几个函数之一,这就是我使用promises的原因。但我发现seedBooks()解析了所创建的样本书中的1到4个

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

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

3 个答案:

答案 0 :(得分:2)

编辑:下面解释了为什么您的代码无法正常工作,以及一般来说如何将非承诺代码转换为承诺的建议。但是,由于Mongoose产生了承诺,你应该使用它们而不是使用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));
}

如果您愿意,还可以让您访问返回的newBook

答案 1 :(得分:1)

您在启动asEached请求后立即同步解析Promise,这些请求是异步的。您可以尝试以下方法:

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 :(得分:1)

如果你使用的是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
});