将promise函数推入数组。使用Promise.all。承诺早日解决

时间:2019-12-13 12:32:23

标签: javascript node.js promise

我对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然后通过电子邮件发送?

任何帮助表示感谢,谢谢!

3 个答案:

答案 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"
// ]
相关问题