繁体   English   中英

承诺在forEach循环完成之前解决

[英]Promise resolves before forEach loop completes

我正在构建我的第一个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(); }); } 

我是否理解或使用了诺言并做出了错误的解决? 任何帮助表示赞赏。 谢谢!

编辑:下面说明了为什么您的代码无法正常工作,以及有关如何将非承诺代码转换为承诺的建议。 由于猫鼬产生了诺言,因此,您应该使用那些new Promise而不是使用new Promise 请参阅Olegzandr对此的回答


由于您正在立即调用resolve()因此Promise正在立即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的好处。

如果您使用猫鼬,则可以执行以下操作:

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

在您开始异步的forEached请求之后,您正在同步解决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 */ })

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM