节点js暂停,而循环等待直到内部函数完全执行?

时间:2019-08-13 17:45:21

标签: javascript node.js

我正在编码一个发布请求,该请求将下载所有URL HTML,将其压缩并发送回电子邮件。这一切都应该在后端进行。我将所有数据存储在一个数组中,并提取第一个元素以开始这些操作。

  • 我有一个while循环,在其中调用了一些函数。每个函数都会在特定时间执行。
  • 我使用了async,await和诺言,以确保它们在 其他。

    出现我的问题。

  • 我的while循环在所有 里面的函数被执行。

app.post('/?', async (req, res) => {
    var urls = req.query.urls
    var email = req.query.email;

    var new_stack = [urls, email]
    stack.push(new_stack)
    res.send("Mail sent")
    if (isFunctionRunning === false) { //initially it is false
        console.log(isFunctionRunning, stack.length)
        send_mails();
    }
});

const getGoogleIndexHTML = (url) => {
    return new Promise((resolve, reject) => {
        request(url, (err, res, body) => err ? reject(err) : resolve(body))
    })
}

const some_function_to_download = async (url) => {
    try {
        const a = url.split(".")
        let googleIndexHTML = await getGoogleIndexHTML(url)
        await fs.writeFile(directory + '/' + a[1] + '.html', googleIndexHTML, (err) => {
            if (err) throw err
        })
        console.log('File created.')
    } catch (err) {
        console.log(err)
    }
}

const html_to_zip_file = async () => {
    await zipper.zip(directory, function (error, zipped) {
        if (!error) {
            zipped.compress();
            zipped.save('./package.zip', function (error) {
                if (!error) {
                    console.log("Saved successfully !");
                }
            });
        } else {
            console.log(error)
        }
    })
}
const send_mails = async () => {
    while (stack.length > 0) {
        isFunctionRunning = true
        var a = stack.shift()
        var urls = a[0]
        var collection_urls = urls.split(",");
        var to_email = a[1]
        rimraf(directory, function () {
            console.log("done");
        });

        fs.mkdirSync(directory);
        for (url of collection_urls) {
            await some_function_to_download(url); // 5 sec per download
        }
        await html_to_zip_file() // takes 5 sec to zip
            .then(result => {
                transporter.sendMail(set_mail_options(to_email))  //2 sec to send mail
                    .then(result => {
                        console.log("Mail sent")
                    })
                    .catch(err => {
                        console.log(err)
                    })
            })
            .catch(err => {
                console.log(err)
            })
            console.log("reached")   // this is reached before zip is done and mail sent. I want to prevent this
    }
    isFunctionRunning = false
}

2 个答案:

答案 0 :(得分:0)

尝试使用以下

while (stack.length > 0) {
    isFunctionRunning = true
    var a = stack.shift()
    var urls = a[0]
    var collection_urls = urls.split(",");
    var to_email = a[1]
    rimraf(directory, function () {
        console.log("done");
    });

    fs.mkdirSync(directory);
    for (url of collection_urls) {
        await some_function_to_download(url); // 5 sec per download
    }
    try {
       const result = await html_to_zip_file() // takes 5 sec to zip
       const sendMailResult = await transporter.sendMail(set_mail_options(to_email))
    } catch(e) 
      {
       console.log(e)
      }

    console.log("reached") 
}

因为html_to_zip_file()和sendMail函数是独立的 我们可以使用

const result = await Promise.all([html_to_zip_file(),transporter.sendMail(set_mail_options(to_email))]);

答案 1 :(得分:0)

  • 您需要在transporter.sendMail中返回sendMail,在fs.writeFile中返回someFunctionToDownload,并在zipper.zip中返回htmlToZipFile,否则将赢得await不能按预期工作(我假设他们实际上确实在兑现承诺,我只熟悉fs.writeFile
  • 也:CamelCase用在JS中,而不是snake_case?
  • 您确定rimraf是同步的吗?
const sendMails = async () => {
  while (stack.length > 0) {
    isFunctionRunning = true;
    const [urls, toEmail] = stack.shift();
    var collectionUrls = urls.split(",");

    rimraf(directory, function() {
      console.log("done");
    });

    await fs.mkdir(directory);

    await Promise.All(collectionUrls.map(someFunctionToDownload)); // 5 sec per download

    await htmlToZipFile() // takes 5 sec to zip
      .then(result => transporter.sendMail(set_mail_options(toEmail))) //2 sec to send mail
      .then(result => {
        console.log("Mail sent");
      })
      .catch(err => {
        console.log(err);
      });

    console.log("reached"); // this is reached before zip is done and mail sent. I want to prevent this
  }
  isFunctionRunning = false;
};

const someFunctionToDownload = async url => {
  const a = url.split(".");
  const googleIndexHTML = await getGoogleIndexHTML(url);
  return fs.writeFile(`${directory}/${a[1]}.html`, googleIndexHTML, err => {
    if (err) throw err;
  });
};

const htmlToZipFile = async () => {
  return zipper.zip(directory, function(error, zipped) {
    if (!error) {
      zipped.compress();
      zipped.save("./package.zip", function(error) {
        if (!error) {
          console.log("Saved successfully!");
        }
      });
    } else {
      console.log(error);
    }
  });
};