簡體   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