简体   繁体   English

如何使用异步、等待和承诺?

[英]How to use async, await and promises?

I am building a web scraper to get all of user's submissions on codeforces.我正在构建一个 web 刮板来获取所有用户在 codeforces 上的提交。 I don't know much about async, await, promises.我对 async、await、promise 了解不多。 I have used axios (promise based) to request codeforces and cheerio to parse HTML.我已经使用 axios(基于承诺)请求 codeforces 和cheerio 来解析 HTML。

app.post("/", (req, res) => {
  const usernameorhandle = req.body.userName;
  getstatus(usernameorhandle).then ( ()=> {
      var output = fs.createWriteStream(__dirname + '/Data/solutions.zip');
      var archive = archiver('zip', {
        zlib: { level: 9 } // Sets the compression level.
      });
      output.on('close', function() {
        console.log(archive.pointer() + ' total bytes');
        console.log('archiver has been finalized and the output file descriptor has closed.');
      });
      output.on('end', function() {
        console.log('Data has been drained');
      });
      res.attachment(__dirname + "/Data/Problems", 'Codeforces-Solutions');
      archive.pipe(res);
      archive.directory(__dirname + "/Data/Problems", 'Codeforces-Solutions');
      archive.finalize();
    }) })

I am using to accept post request.我用来接受发布请求。 I am putting all the solutions into a folder and creating zip folder and then send to res.我将所有解决方案放入一个文件夹并创建 zip 文件夹,然后发送到 res。

Below is my getstatus function.下面是我的getstatus function。

    async function getstatus(handle){
  return new Promise(async (resolve, reject)=> {
    console.log("HELLLLLLLOOOOOOOO");
    await axios.get("https://codeforces.com/api/user.status?handle=" + handle + "&from=1")
      .then(response => {
        if(response.data.status === 'OK'){
          let results = response.data.result;
          console.log("AAAAAAAAAAAAAAAAAAAAAAAa");
          scrape(results).then( () =>{
            console.log("DONE");
            resolve();
          })
          .catch(err => console.log(err));
          // resolve();
        }
        else console.log(submissions.comment);
      })
  })

}

I use scrape function to obtain HTML data and put to folder named Problems.我使用刮取 function 来获取 HTML 数据并放入名为 Problems 的文件夹中。

async function scrape (results){
  console.log("inside scrape");
  //  console.log("HELLO");
  return new Promise( async (resolve, reject) => {
    await results.forEach(async (result)=> {
      if(result.verdict === 'OK'){
        await axios.get("https://codeforces.com/contest/" + result.contestId + "/submission/" + result.id)
        .then(solutionPage => {
          const $ = cheerio.load(solutionPage.data);
          const path = "/home/srujan/Desktop/crawlerapp/Data/Problems/" + result.problem.name + ".cpp";
           fs.writeFile(path, $('#program-source-text').text(), function(err){
            if(err){
              console.log(err);
            }
            else{
              console.log("Saved file");
            }
          })
        })
        .catch( error => {
          console.log("HTML PARSE ERROR" + error);
        })
     }
    })
    console.log("hey");
    resolve();

  })

The problem is I am getting问题是我得到

HELLLLLLLOOOOOOOO
AAAAAAAAAAAAAAAAAAAAAAAa
inside scrape
hey
DONE
saved file
saved file
...

Browser downloads after DONE and then files are saved.完成后浏览器下载,然后保存文件。 I am new to js and don't know why I am getting this.我是 js 新手,不知道为什么会这样。

PS: I know this is very long question. PS:我知道这是一个很长的问题。 I tried reading a lot about this.我尝试阅读很多关于此的内容。 Didn't understand properly how to do that.没有正确理解如何做到这一点。 I copy pasted some code which I didn't understand like how to zip a folder.我复制粘贴了一些我不明白的代码,例如如何将 zip 复制到文件夹中。

The problem is to use result.forEach Try to use a simple for(let i = 0; i < result.length; i++) without async.问题是使用 result.forEach 尝试使用没有异步的简单 for(let i = 0; i < result.length; i++)。

If that doesn't work, try to return anything inside the then.如果这不起作用,请尝试在 then 中返回任何内容。

This is how I would construct getstatus function with await async这就是我将如何使用等待异步构造getstatus function

 async function getstatus(handle) {

    const response = await axios.get("https://codeforces.com/api/user.status?handle=" + handle + "&from=1")

    if(response.data.status === 'OK') {

      let results = response.data.result;

      try {
        await scrape(results);
        console.log("DONE");
      }
      catch(error) {
      }

    }
}

and scrape function accordingly...并相应地scrape function...

const fs = require('fs').promises;

async function scrape (results) {
  results.forEach(async (result)=> {

   if(result.verdict === 'OK') {
    const solutionPage = await axios.get("https://codeforces.com/contest/" + result.contestId + "/submission/" + result.id)

    const $ = cheerio.load(solutionPage.data);
    const path = "/home/srujan/Desktop/crawlerapp/Data/Problems/" + result.problem.name + ".cpp";

    try {
      await fs.writeFile(path, $('#program-source-text').text())
      console.log("Saved file");
    }
    catch(error) {
    }
  }
 }
}             

forEach(callback) executes callback . forEach(callback)执行callback If callback returns a promise (ie, it's an async function), the promise won't be resolved before calling the callback on the next element of the array.如果callback返回 promise(即,它是一个异步函数),则在对数组的下一个元素调用回调之前,不会解析 promise。

So, basically, you can't use async functions inside forEach... But you can use for-loops or Promise.all instead!所以,基本上,你不能在 forEach 中使用异步函数......但是你可以使用 for-loops 或Promise.all来代替!

Also, fs.writeFile works with sync + callback, but there exists a fs.promise.writeFile that uses promises instead.此外, fs.writeFile与同步 + 回调一起使用,但存在一个fs.promise.writeFile使用 Promise 代替。

Here's a scrape function that should work better:这是一个应该工作得更好的刮擦 function:

async function scrape(results) {
  for (const result of results) {
    if(result.verdict === 'OK') {
      const solutionPage = await axios.get("https://codeforces.com/contest/" + result.contestId + "/submission/" + result.id);
      const $ = cheerio.load(solutionPage.data);
      const path = "/home/srujan/Desktop/crawlerapp/Data/Problems/" + result.problem.name + ".cpp";
      try {
        await fs.promises.writeFile(path, $('#program-source-text').text());
      } catch(err) { console.log(err) }
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM