[英]Promises not waiting for each other in my nodejs controller
我在這里有4個諾言,我認為它將執行第一個諾言,然后等到其完成,然后再執行下一個諾言,等到完成並再執行下一個諾言,依此類推。
但是這里發生的是它一次運行所有這些,並且不等待任何事情完成。
這是我的諾言鏈:
//
// Run the promises
//
findBanks
.then(findReceipts)
.then(findExpenses)
.then(sendResult)
.catch(err => {
console.error(err);
console.log("getbankAccountReport ERR: " + err);
res.json({error:true,err})
});
這是我的console.log的輸出
=====findAllBank=====
=====findAllReceipt=====
=====findAllExpense=====
=====RESOLVE findAllBank=====
=====sendResult=====
=====RESOLVE sendResult=====
=====RESOLVE findAllReceipt=====
=====RESOLVE findAllExpense=====
我不理解諾言正確嗎?
無論如何,這是我的nodejs控制器:
exports.getBankAccountReport = function(req, res) {
//
// Find all bank accounts
//
var bankModel = require('../models/bankModel');
var bankTable = mongoose.model('bankModel');
var bankArray = [];
var findAllBank = new Promise(
(resolve, reject) => {
console.log("=====findAllBank=====")
bankTable.aggregate([
...lots of mongo stuff...
],function(err, data) {
if (!err) {
bankArray = data;
console.log("=====RESOLVE findAllBank=====")
resolve(data);
} else {
reject(new Error('findBank ERROR : ' + err));
}
});
});
//
// Find the RECEIPT for each bank account
//
var receiptModel = require('../models/receiptModel');
var receiptTable = mongoose.model('receiptModel');
var receiptArray = [];
var findAllReceipt = new Promise(
(resolve, reject) => {
console.log("=====findAllReceipt=====")
receiptTable.aggregate([
...lots of mongo stuff...
], function (err, data) {
if (!err) {
receiptArray = data;
console.log("=====RESOLVE findAllReceipt=====")
resolve(data);
} else {
reject(new Error('findReceipts ERROR : ' + err));
}
});
});
//
// Find the EXPENSE for each bank account
//
var expenseModel = require('../models/expenseModel');
var expenseTable = mongoose.model('expenseModel');
var expenseArray = [];
var findAllExpense = new Promise(
(resolve, reject) => {
console.log("=====findAllExpense=====")
expenseTable.aggregate([
...lots of mongo stuff...
], function (err, data) {
if (!err) {
expenseArray = data;
console.log("=====RESOLVE findAllExpense=====")
resolve(data);
} else {
reject(new Error('findExpense ERROR : ' + err));
}
});
});
var sendResult = function(data) {
var promise = new Promise(function(resolve, reject){
console.log("=====sendResult=====")
res.json({error:false,
"bank":bankArray,
"receipt":receiptArray,
"expense":expenseArray})
console.log("=====RESOLVE sendResult=====")
resolve();
});
return promise;
};
//
// Run the promises
//
findAllBank
.then(findAllReceipt)
.then(findAllExpense)
.then(sendResult)
.catch(err => {
console.error(err);
console.log("getbankAccountReport ERR: " + err);
res.json({error:true,err})
});
}
您需要將Promises包裝在函數中
var findAllBank = function() {
return new Promise(
(resolve, reject) => {
console.log("=====findAllBank=====")
bankTable.aggregate([
...lots of mongo stuff...
],function(err, data) {
if (!err) {
bankArray = data;
console.log("=====RESOLVE findAllBank=====")
resolve(data);
} else {
reject(new Error('findBank ERROR : ' + err));
}
});
});
});
解析后,將使用resolve()函數中傳遞的數據來調用鏈中的下一個函數。
不要混淆Promise和構建它的功能
創建new Promise(executor)
,您將實例化一個新對象,該對象將具有兩種方法(對象的功能) .then(resolveCB [, rejectCB])
和.catch(rejectCB)
。
動漫是要知道,每當一個過程完成時,它是否成功或失敗,然后相應地繼續。
var myFirstPromise = new Promise(function executor(resolve, reject) { resolve('resolved'); });
換句話說,一旦executor
定義的承諾得到解決,這些方法將用於繼續您的過程。 它既可以fulfilled
並調用resolveCB
回調(使用then
),也可以rejected
並調用rejectCB
回調(同時使用then
和catch
)。 回調(resolveCB或rejectCB)是一個函數,而不是Promise本身,即使該回調可能返回Promise。
myFirstPromise
.then(function resolveCB(result) { console.log(result); }) //you can use a 2nd callback for rejection at this point
.catch(function rejectCB(err) { console.log(err); });
myFirstPromise
.then(
function resolveCB(result) { console.log(result); } // if resolved
, function rejectCB(err) { console.log(err); } // if rejected
)
.catch(function rejectCB(err) { console.log(err); }); // NEVER forget the last catch, just my 2cents :)
我們看到的輸入.then()
和.catch()
但對於它們的返回值? 他們兩個都將返回一個新的Promise。 這就是為什么你可以鏈.then()
的和.catch()
的。
myFirstPromise
.then(function resolveCB1(result) { console.log(result); })
.then(function resolveCB2(result) { console.log(result); }) // console.log is called but result is undefined
.catch(function rejectCB1(err) { console.log(err); });
myFirstPromise
.then(function resolveCB3(result) {
throw 'I threw an exception'; // an exception is thrown somewhere in the code
console.log(result);
})
.then(function resolveCB4(result) { console.log(result); })
.catch(function rejectCB2(err) { console.log(err); }); // a promise in the chain get rejected or error occured
在前面的示例中,我們看到第二個.then()
被命中,但result
未定義。 第一個.then()
已滿文件返回的承諾.then()
但執行者未將其傳遞給resolve回調resolveCB2
傳遞任何值。 在第二種情況下, resolveCB3
發生了一個異常,該異常被拒絕,因此調用了rejectCB2
。 如果我們希望我們的解析回調接收一個參數,我們必須通知exector。 為此,最簡單的方法是使回調返回一個值:
myFirstPromise
.then(function resolveCB1(result) {
console.log(result);
result += ' again';
return result;
})
.then(function resolveCB2(result) {
console.log(result);
return result;
})
.catch(function rejectCB1(err) { console.log(err); });
如此說來,您已經將所有的內容整合在一起以了解Promise
。 讓我們嘗試以一種更簡潔的方式總結一下:
var myFirstPromise = new Promise(function executor(resolve, reject) { resolve('resolved'); })
, resolveCB = function resolveCB(result) {
console.log(result);
result += ' again';
return result;
}
, resolveLastCB = function resolveLastCB(result) {
console.log(result);
result += ' and again';
return result;
}
, justLog = function justLog(result) {
console.log(result);
return result;
}
;
myFirstPromise
.then(resolveCB)
.then(resolveLastCB)
.then(justLog)
.catch(justLog);
您現在可以很好地對其進行贊美了,這很酷
myFirstPromise
.then(resolveCB)
.then(resolveCB)
.then(resolveCB)
.then(resolveCB)
.then(resolveCB)
.then(resolveCB)
.then(resolveLastCB)
.then(justLog)
.catch(justLog);
但是,如果您的Promise鏈“確實”發生了變化,並且您需要擺脫myFirstPromise
並從resolveCB
開始,該怎么辦? 這只是一個功能,它可以執行,但沒有任何.then()
或.catch()
方法。 這不是一個承諾。 您不能做resolveCB.then(resolveLastCB)
,它將引發錯誤resolveCB.then(不是函數或類似的東西。您可能會認為這是一個嚴重的錯誤,我沒有調用resolveCB
和resolveCB().then(resolveLastCB)
應該能工作嗎?對於那些想到這一點的人來說,還是很不幸的。它仍然是錯誤的resolveCB
返回一個字符串,一些字符,而不是Promise
。
為了避免此類維護問題,您應該知道resolve和reject回調可以返回Promise
而不是值。 為此,我們將使用所謂的工廠模式。 簡單來說,工廠模式就是使用(靜態)函數實例化新對象,而不是直接使用構造函數。
var myFirstPromiseFactory = function myFirstPromiseFactory() {
/*
return new Promise(function executor(resolve, reject) {
resolve('resolved');
});
if you just need to resolve a Promise, this is a quicker way
*/
return Promise.resolve('resolved');
}
, resolveFactory = function resolveFactory(result) {
return new Promise(function executor(resolve, reject) {
result = result || 'I started the chain';
console.log(result);
result += ' again';
return resolve(result); // you can avoid the return keyword if you want, I use it as a matter of readability
})
}
, resolveLastFactory = function resolveLastFactory(result) {
return new Promise(function executor(resolve, reject) {
console.log(result);
result += ' and again';
return resolve(result);
});
}
, justLogFactory = function justLogFactory(result) {
return new Promise(function executor(resolve, reject) {
console.log(result);
return resolve(result);
});
}
;
myFirstPromiseFactory() //!\\ notice I call the function so it returns a new Promise, previously we started directly with a Promise
.then(resolveFactory)
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
// Now you can switch easily, just call the first one
resolveFactory()
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
justLogFactory('I understand Javascript')
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
在數組上迭代時,工廠函數可能會派上用場。 給定輸入,它可以用於產生一個promise數組:
var myFirstPromiseFactory = function myFirstPromiseFactory() {
/*
return new Promise(function executor(resolve, reject) {
resolve('resolved');
});
if you just need to resolve a Promise, this is a quicker way
*/
return Promise.resolve('resolved');
}
, resolveFactory = function resolveFactory(result) {
return new Promise(function executor(resolve, reject) {
result = result || 'I started the chain';
console.log(result);
result += ' again';
return resolve(result); // you can avoid the return keyword if you want, I use it as a matter of readability
})
}
, resolveLastFactory = function resolveLastFactory(result) {
return new Promise(function executor(resolve, reject) {
console.log(result);
result += ' and again';
return resolve(result);
});
}
, justLogFactory = function justLogFactory(result) {
return new Promise(function executor(resolve, reject) {
console.log(result);
return resolve(result);
});
}
, concatValues = function concatValues(values) {
return Promise.resolve(values.join(' '));
}
, someInputs = [
'I am an input'
, 'I am a second input'
, 'I am a third input'
, 'I am yet an other input'
]
;
myFirstPromiseFactory() //!\\ notice I call the function so it returns a new Promise, previously we started directly with a Promise
.then(resolveFactory)
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
// Now you can switch easily, just call the first one
resolveFactory()
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
justLogFactory('I understand Javascript')
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
// Using a factory functions to create an array of promise usable with Promise.all()
var promiseArray = someInputs.map(function(input) {
return justLogFactory(input);
});
Promise.all(promiseArray)
.then(concatValues)
.then(resolveLastFactory)
.then(justLogFactory)
.catch(justLogFactory);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.