承诺在我的nodejs控制器中不等待对方



我在这里得到了 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})
});

这是我控制台的输出.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})
});
}

你需要将你的承诺包装在函数中

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() 函数中传递的数据调用链中的下一个函数。

不要混淆承诺和构建它的函数

创建new Promise(executor)时,实例化一个新对象,该对象将具有两个方法(对象的函数),.then(resolveCB [, rejectCB]).catch(rejectCB)

目标是知道,无论何时完成一个过程,它是成功的还是失败的,并相应地继续。

var myFirstPromise = new Promise(function executor(resolve, reject) { resolve('resolved'); });

换句话说,一旦解决了executor定义的承诺,这些方法就会用于继续您的流程。它可以获取fulfilled并调用resolveCB回调(使用then),也可以rejected并调用rejectCB回调(使用thencatch)。回调(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()的输入,但它们的返回值呢?他们俩都会返回一个新的承诺。这就是为什么你可以链接.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()已满,但执行者没有传递给解析回调resolveCB2的值。在第二种情况下,resolveCB3中发生了异常,它被拒绝rejectCB2因此被调用。如果我们希望我们的解析回调接收参数,我们必须通知执行者。为此,最简单的方法是让回调返回一个值:

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

但是,如果你的承诺链"真的"改变了,你需要摆脱myFirstPromise,而是从resolveCB开始呢?它只是一个函数,可以执行,但没有任何.then().catch()方法。这不是承诺。你不能做resolveCB.then(resolveLastCB),它会如何解决错误CB.then(不是函数或类似的东西。你可能会认为这是一个严重的错误,我没有打电话给resolveCBresolveCB().then(resolveLastCB)应该工作?不幸的是,对于那些考虑过这一点的人来说,这仍然是错误的。resolveCB返回一个字符串、一些字符,而不是一个Promise

为了避免此类维护问题,您应该知道解析和拒绝回调可以返回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);

工厂函数在迭代数组时可能会派上用场。它可用于在给定输入的情况下生成一系列承诺:

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

相关内容

  • 没有找到相关文章

最新更新