我对Node.js很陌生。我对promise函数和Promise.all
有问题。
我误解了一些概念,或者我做错了什么。我已经尝试过对该主题进行研究,但是找不到针对我特定问题的正确答案。
情况如下。
我有一个promise函数来生成pdf,它返回生成的pdf的路径。
var myNicePdfCreator={
setting1: value1,
setting2: value2,
createPdf: function(customerId){
return new Promise(function(resolve, reject){
dataBase.fetchForId(customerId).then(function(data){
somePdfLibrary.createPdf.then(function(path){
resolve(path);
},function(err){
//error creating pdf
reject(err);
});
},function(err){
//error fetching from db
reject(err);
}
})
}
}
我有一个promise函数,该函数会获取电子邮件地址和pdf的路径,然后发送带有附件pdf的电子邮件
var myNiceMailSender={
setting1: value1,
setting2: value2,
sendMail: function(email, path){
return new Promise(function(resolve, reject){
someMailLibrary.createMail(email, title, message, attachment).then(function(status){
resolve(status);
},function(err){
reject(err);
});
});
}
}
我想对数组中的每个对象执行此操作(例如,获取每个客户的报告,然后将其通过电子邮件发送给他们)。我试图提出一个Promise函数,该函数首先创建pdf,然后发送邮件,然后使用forEach
循环将诺言推送到数组,然后使用Promise.all
来制作所有PDF和发送邮件。但是无论我如何尝试,每当我将一个诺言推送到一个数组时,即使我只是尝试将两个诺言函数之一推送到该数组,它也已经在我使用Promise.all
之前就已经解决了。
如果我这样做;
var promises=[];
AllCustomers.forEach(customer){
promises.push(myNicePdfCreator.createPdf(customer.id));
});
当我将PDF推送到数组时,将直接创建PDF。我什至不需要打{{1}}。
如果我尝试将promise函数推送到发送电子邮件的数组,则同样,邮件将立即发送。
有人能向我指出正确的方向,为什么我将诺言推到数组时诺言却被解决?
是否有更好的方法来创建PDF然后通过电子邮件发送?
任何帮助表示感谢,谢谢!
答案 0 :(得分:1)
我想您想要的是在开始发送电子邮件之前弄清所有PDF文件。就像已经说过的那样,当您调用Promise时,除非您有.then或等待它,否则它的执行不会等待。
const promises=[];
for(const customer of AllCustomers){
promises.push(myNicePdfCreator.createPdf(customer.id));
});
Promise.all(promises).then((paths) => {
// paths is going to have an array with the paths of all the pdfs already generated
});
使用此代码,在Promise.all中将等待所有PDF生成。因此,在那时,您可以发送电子邮件。
答案 1 :(得分:1)
如果您要创建未解决的,未处理的承诺数组,从而为每个客户创建报告,然后通过电子邮件将该客户发送给电子邮件,则它看起来像这样:
const pfuncs = AllCustomers.map(customer => {
return async function() {
const pdfPath = await myNicePdfCreator.createPdf(customer.id);
const status = await myNiceMailSendor.sendMail(customer.email, pdfPath);
return {status, pdfPath};
}
})
这将创建一个函数数组-'createPdf'请求尚未开始运行,它正在等待您调用数组中的每个函数。
当您准备发送请求时,您会这样做
const results = await Promise.all(pfuncs.map(f => f()));
现在结果是一个看起来像[{status: 200, pdfPath: ''} , {status: 200, pdfPath: ''}, ...]
答案 2 :(得分:1)
promise在声明时执行。如果您要“锁定”所有promise直到定义了所有promise,则可以将其封装在函数中,并在声明所有内容后进行循环执行
// Await "a" seconds to finish, reject if "a" o "b" are negative
function myPromiseFunction(a, b) {
return new Promise((res, rej) => {
setTimeout(() => {
if (a < 0 || b < 0) {
rej(0);
} else {
res(a+b);
}
}, a * 1000);
})
}
(() => {
let someData = [{a:2,b:2}, {a:10, b:4}];
// Generate promises in functions
let myPromises = someData.map((v) => {
return () => myPromiseFunction(v.a, v.b);
});
// Execute all
myPromises = myPromises.map((promise) => promise());
// ...
})();
Promise.all
函数仅等待所有诺言完成过程,否则任何诺言都会被拒绝。例如:
所有承诺都很好:
// Await "a" seconds to finish, reject if "a" o "b" are negative
function myPromiseFunction(a, b) {
return new Promise((res, rej) => {
setTimeout(() => {
if (a < 0 || b < 0) {
rej(0);
} else {
res(a+b);
}
}, a * 1000);
})
}
(() => {
let someData = [{a:2,b:2}, {a:10, b:4}];
// Generate promises in functions
let myPromises = someData.map((v) => {
return () => myPromiseFunction(v.a, v.b);
});
// Execute all
myPromises = myPromises.map((promise) => promise());
// Await all
Promise.all(myPromises).then(res => {
console.log(res, myPromises);
}).catch(err => {
console.log(err, myPromises);
});
})();
您将在console.log
中打印then
,并且会像这样:
// res: [ 4, 14 ]
// myPromises: [ Promise { 4 }, Promise { 14 } ]
但是,如果您有谁会失败的承诺:
let someData = [{a:10,b:2}, {a:4, b:-4}, {a:2, b:4}];
第二个承诺将被负值拒绝,但是第一个承诺将无法解决(结束10秒),因此catch的输出将是:
// err: 0 (this is the error of the first rejected promise)
// myPromises: [
// Promise { <pending> }, // The rejected promise will not stop the pendings
// Promise { <rejected> 0 }, // The rejected promise
// Promise { 6 }, // A "resolved" or maybe "pending"
// ]