简体   繁体   English

Function 代码未按正确顺序执行,异步等待执行错误

[英]Function code isn't executed in the right order, async-wait is implemented wrongly

What I'm trying to do in my endpoint, is:我在端点中尝试做的是:

  1. Make an API call, which returns a JSON进行 API 调用,该调用返回 JSON
  2. for each item: search in our database for it对于每个项目:在我们的数据库中搜索它
  3. If it's found, skip it.如果找到,请跳过它。
  4. If it's not found, push it in an array "Response"如果未找到,将其推送到数组“响应”中

This is my code:这是我的代码:

app.get("/test", (req,res) => {

  spotifyApi.getUserPlaylists({ limit: 50 })
  .then(function(data) {
    let finalres = [];
    const tbp = data.body.items;
    // res.send('ok stop loading');
    
    tbp.forEach(element => locateit(element,finalres));

    console.log('This is the length of finalres, which should be 1:', finalres.length);
    finalres.forEach(item =>{console.log(item)});

    function locateit(item, finalres){
      const thisplaylistid = item.id;

      collection.find({ "id" : thisplaylistid }).toArray((error, result) => {
        if(error) {
          return res.status(500).send(error);
        }

        if(result.length == 0) {    // if we don't find this playlist in our DB
          console.log('This playlist is not in our database: ');
          console.log(thisplaylistid);
          finalres.push(thisplaylistid);
        }
        else{  //if it's already in our DB
          console.log('This item is in our database.'); //This should be printed first, six times.
        }
      });
    };
  });
});

The content of data.body.items is 7 items, where only the first 6 of them are in our DB. data.body.items的内容是 7 个项目,其中只有前 6 个在我们的数据库中。 This means, that the last item, should be pushed in finalres .这意味着,最后一项应该被推入finalres Therefore, the expected console outcome should be:因此,预期的控制台结果应该是:

This item is in our database.
This item is in our database.
This item is in our database.
This item is in our database.
This item is in our database.
This playlist is not in our database: 
3uDLmuYPeRUxXouxuTsWOe
This is the length of finalres, which should be 1: 1
3uDLmuYPeRUxXouxuTsWOe

But instead, I get this:但相反,我得到了这个:

This is the length of finalres, which should be 1: 0
This should be displayed first, six times.
This should be displayed first, six times.
This should be displayed first, six times.
This should be displayed first, six times.
This should be displayed first, six times.
This should be displayed first, six times.
This playlist is not in our database: 
3uDLmuYPeRUxXouxuTsWOe

It is obviously not executed in the right order.它显然没有按正确的顺序执行。 I tried to use async-wait, but I'm struggling to understand where/how it should be implemented.我尝试使用异步等待,但我很难理解应该在哪里/如何实现它。 Any help?有什么帮助吗? This is the part where I tried it, but I get the same console outcome as before:这是我尝试过的部分,但我得到了与以前相同的控制台结果:

async function locateit(item, finalres){
      const thisplaylistid = item.id;

      await collection.find({ "id" : thisplaylistid }).toArray((error, result) => {
...

Update更新

After reading more about async-wait and promises, I tried to do it this way, but I'm still getting the same output.在阅读了有关异步等待和承诺的更多信息后,我尝试这样做,但我仍然得到相同的 output。

app.get("/test", (req,res) => {

  spotifyApi.getUserPlaylists({ limit: 50 })
  .then(function(data) {
    let finalres = [];
    const tbp = data.body.items;
    // res.send('ok stop loading');
    
    for (const playlist of tbp) {
      async function doWork() {
        const found = await indb(playlist.id); //returns t/f if found or not found
        if (!found){
          finalres.push(playlist);
        }
      }
      doWork();
    }
    console.log('This is the length of finalres and it should be 1: ',finalres.length);
  })
});

and the indb function looks like that: indb function 看起来像这样:

function indb(thisplaylistid){
  return new Promise((resolve, reject) =>{
      console.log('Searching in our DB...');
      collection.find({ "id" : thisplaylistid }).toArray((error, result) => {
          if(result.length == 0) {    // if we don't find this playlist in our DB
              console.log('This playlist is not in our database: ');
              console.log(thisplaylistid);
              resolve(false); //returns the id
          }
          else{  //if it's already in our DB
              console.log('This item is in our database.'); //This should be printed first, six times.
              resolve(true);
          }
      });
  })
}

The problem here is that forEach resolves always resolves as void, no matter if you have async promises running within.这里的问题是,无论您是否有异步承诺在其中运行,forEach 解析总是解析为 void。

So, your code will return before executing the statements within the forEach因此,您的代码将在执行 forEach 中的语句之前返回

The correct would be wait for all promises to resolve using #Promise.all正确的做法是使用#Promise.all等待所有承诺解决

Try this instead:试试这个:

Updated更新
Using promise as suggested by Bergi instead of callback ( preferable )按照 Bergi 的建议使用 promise 而不是回调(更可取)

app.get("/test", (req, res) => {

  spotifyApi.getUserPlaylists({ limit: 50 })
    .then((data) => {
      // :refac: more meaningful variable names
      const playlists = data.body.items
      return Promise.all(
        playlists.map(
          // :refac: destructuring to get only the id, other ain't necessary
          async({ id }) => 
              collection.find({ id }).toArray()  
        )
      )
      .then(playlistsById => 
        // :refac: no error occurred fetching playlists
        const nonEmptyPlaylists = playlistsById.filter(playlistById => playlistById.length !== 0)
        res.status(200).send(nonEmptyPlaylists)
      )
      .catch(error => {
        // :refac: some error occurred at searching some playlist
        console.log('error', error) 
        // :refac: if you might expect that is going to throw an error here, the code shouldn't be 500
        return res.status(400).send(error)
      })
    })
})

As others mentioned, your usage of async/await is wrong.正如其他人提到的,您对 async/await 的使用是错误的。 I believe this should work and do what you want, and as a bonus its shorter and easier to read.我相信这应该可以工作并做您想做的事情,并且作为奖励,它更短且更易于阅读。 mastering async and await will simplify your life and save you from callback/promise hell, i highly recommend it掌握 async 和 await 将简化您的生活并让您免于回调/承诺地狱,我强烈推荐它

app.get("/test", async (req, res) => {
    
  try {
    
    const data = await spotifyApi.getUserPlaylists({ limit: 50 });

    const tbp = data.body.items;

    const results = [];

    for(let item of tbp) {
      const found = await indb(item.id);
      if(!found){
        results.push(item);
      }
    }
    return res.status(200).send(results);
  }
  catch(err) {
    return res.status(400).send(err);  
  }
  
});

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

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