Javascript 功能代码为';t按正确的顺序执行,异步等待执行错误

Javascript 功能代码为';t按正确的顺序执行,异步等待执行错误,javascript,node.js,async-await,Javascript,Node.js,Async Await,我在端点中尝试做的是: 进行API调用,该调用返回JSON 对于每个项目:在我们的数据库中搜索它 如果找到了,跳过它 如果找不到,则将其放入数组“Response” 这是我的代码: app.get("/test", (req,res) => { spotifyApi.getUserPlaylists({ limit: 50 }) .then(function(data) { let finalres = []; const tbp = data

我在端点中尝试做的是:

  • 进行API调用,该调用返回JSON
  • 对于每个项目:在我们的数据库中搜索它
  • 如果找到了,跳过它
  • 如果找不到,则将其放入数组“Response”
  • 这是我的代码:

    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) => {
    ...
    
    使现代化 在阅读了更多关于异步等待和承诺的内容后,我尝试了这样做,但仍然得到了相同的输出

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

    这里的问题是,forEach解析总是解析为void,不管您是否在其中运行异步承诺

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

    正确的做法是等待所有承诺通过使用

    请尝试以下方法:

    已更新
    按照Bergi的建议使用promise而不是callback(更好)


    正如其他人提到的,使用async/await是错误的。我相信这本书应该很管用,可以做你想做的事情,而且它更简短,更容易阅读。我强烈建议,掌握async和Wait将简化您的生活,并将您从回调/承诺地狱中解救出来

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

    问题是(而且
    locateit
    不会返回承诺,是的)。
    collection
    看起来像mongodb,所以
    toArray
    应该已经返回了承诺,如果你只是不通过回调,如果你使用
    。在承诺链的末尾,catch
    ,没有理由等待并传递一个
    异步
    函数来表示(这不会正确处理返回的承诺)。是的,我想是这样的,但他没有提到这是专门使用mongo的,我不想自己推断。因此,我使用了回调方式来与他的代码类似(即使我不喜欢这种方式)。感谢您提供的快速信息,我不知道,我会在这里用这两个建议进行更新,首先感谢Bergi,感谢@FelipeMalara和@Bergi的回复!我确实在使用express和mongodb——我认为这与此无关,因此我没有使用标签。我测试了菲利佩的回答,但它与我试图做的相反
    playlisbyd
    包含已存在于我的数据库中的播放列表,而我希望获取不存在的播放列表。这就是为什么我最初使用
    finalres
    数组将数据库中找不到的播放列表推送到那里。我们很高兴(:,哦,明白了,是的,您需要更改该过滤器以检索实际长度为===0或其他内容,但错误确实与异步句柄有关。这确实更清晰,更容易理解,非常感谢!我唯一需要做的更改是
    for(tbp的let项)
    而不是循环中的
    ,否则,
    将变得
    未定义
    ,HTTP响应类似于JSON中每个字段的索引。如果您同意该更改,请编辑您的回复,以便我可以选择它作为答案。@neopeach good catch。更新了答案。我实际上从未使用过它我以前对数组使用过这种语法,但不知道这是可能的。
    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);  
      }
      
    });