【问题标题】:Function code isn't executed in the right order, async-wait is implemented wrongly函数代码未按正确顺序执行,异步等待执行错误
【发布时间】:2020-12-31 06:50:48
【问题描述】:

我在端点中尝试做的是:

  1. 进行 API 调用,返回 JSON 格式
  2. 对于每个项目:在我们的数据库中搜索它
  3. 如果找到,请跳过它。
  4. 如果未找到,则将其推送到数组“响应”中

这是我的代码:

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.
        }
      });
    };
  });
});

data.body.items 的内容是 7 项,其中只有前 6 项在我们的数据库中。这意味着,最后一项应该被推送到finalres。 因此,预期的控制台结果应该是:

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

但是,我得到了这个:

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

显然没有按正确的顺序执行。我尝试使用异步等待,但我很难理解应该在哪里/如何实现它。有什么帮助吗? 这是我尝试过的部分,但我得到了与以前相同的控制台结果:

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

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

更新

在阅读了有关 async-wait 和 Promise 的更多信息后,我尝试这样做,但仍然得到相同的输出。

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);
  })
});

indb 函数如下所示:

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);
          }
      });
  })
}

【问题讨论】:

标签: javascript node.js async-await


【解决方案1】:

这里的问题是 forEach 解析总是解析为 void,无论您是否有异步 Promise 在其中运行。

因此,您的代码将在执行 forEach 中的语句之前返回

正确的做法是使用#Promise.all 等待所有承诺解决

试试这个:

更新
按照 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)
      })
    })
})

【讨论】:

  • collection 看起来像 mongodb,所以 toArray 应该已经返回一个承诺,如果你只是不通过回调
  • 如果你在 Promise 链的末尾使用 .catch,则没有理由 await 并传递 async 函数来表达(这将无法正确处理返回的 Promise) .
  • 是的,我认为,但由于他没有提到这是专门使用 mongo 我不想自己推断。所以我使用回调的方式来和他的代码类似(即使我不喜欢这种方式)。感谢您的快速信息,我不知道,将在这里更新它的两个建议,感谢 Bergi ?。
  • 首先,感谢@FelipeMalara 和@Bergi 的回复!我确实在使用 express 和 mongodb——我认为这无关紧要,因此我没有使用这些标签。我测试了 Felipe 的回复,但它与我正在尝试做的相反。 playlistsById 包含我的数据库中已经存在的播放列表,而我想获取那些不存在的播放列表。这就是为什么我最初使用finalres 数组来推送我的数据库中没有的任何播放列表。
  • 我们很高兴(:,哦,明白了,是的,您需要更改该过滤器以检索长度实际上是 === 0 或其他东西的位置,但该错误确实与异步句柄有关
【解决方案2】:

正如其他人所提到的,您对 async/await 的使用是错误的。我相信这应该可以工作并做您想做的事情,并且作为奖励,它更短且更易于阅读。掌握 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);  
  }
  
});

【讨论】:

  • 这个确实比较清晰易懂,非常感谢!我必须做的唯一更改是循环中的for(let item of tbp) 而不是in,否则item 将变为undefined,并且HTTP 响应看起来像JSON 中每个字段的索引。如果您同意该更改,请编辑您的回复,以便我选择它作为答案。
  • @neonpeach 不错。更新了答案。实际上,我以前从未在数组中使用过这种语法,也不知道这是可能的。
猜你喜欢
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
相关资源
最近更新 更多