检测异步代码内循环的结束,该代码位于该循环内另一个函数的内部

时间:2019-01-07 14:12:03

标签: javascript

所以我有这段代码:

  for (let i = 0; i < array.length; i++) {
    let url = array[i];
    YTDL.getInfo(url, function(err, info) {
      if (err) {
        message.channel.send("There was an error while checking information about a video, try again soon.");
        throw err;
      }
      songEmbed.addField("Title:", info.title);
      if (i == array.length - 1) message.channel.send(songEmbed);
    });
  }

问题是在for循环结束后调用了YTDL.getInfo()内部的函数,但是我只需要在最后一次迭代(请参见代码)之后才调用message.channel.send(songEmbed)我最好自己解决这个问题,例如使用array.forEach(),但是我想不通如何在YTDL.getInfo()内部将正确的元素索引传递给此函数,希望您能理解我。

5 个答案:

答案 0 :(得分:0)

从单个网址获得响应需要花费时间,更不用说数组中的多个网址了。这是一个异步调用,因此要等待响应,您应该使用Promises。那里有很多例子。 https://medium.freecodecamp.org/javascript-from-callbacks-to-async-await-1cc090ddad99

应该会有所帮助

答案 1 :(得分:0)

尝试了解javascript中同步/异步的基础。有最流行的资源可用于此目的:

https://www.youtube.com/watch?v=cCOL7MC4Pl0

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

https://www.youtube.com/watch?v=8aGhZQkoFbQ

您的错误是从sync for循环运行async函数,因此即使在函数的第一次运行中,您也将获得最后一项的索引。花一些时间发送我给您的链接以及该主题,这将对您有很大帮助。


您的问题和解决方案如何?只需使用异步for循环,即可熟悉的链接:

https://hackernoon.com/async-await-essentials-for-production-loops-control-flows-limits-23eb40f171bd

https://codeburst.io/asynchronous-code-inside-an-array-loop-c5d704006c99

答案 2 :(得分:0)

您遇到的事情是使用javascript,异步方法最令人沮丧/最强大的事情之一。我猜在getInfo方法中,您正在进行某种形式的ajax调用。为了节省时间和资源,JavaScript将使调用落入后台,从而不会阻止下一个代码的运行。这通常很好,因为它可以一次运行很多javascript,并且页面加载比同步时要快得多。但是对您来说,这意味着在访问info.title时,实际上并没有设置它。解决此问题的简单而肮脏的方法是在要在for循环中调用的内容周围添加setTimeout调用。像这样:

setTimeout(function(){ 
      if (err) {
        message.channel.send("There was an error while checking information about a video, try again soon.");
        throw err;
      }
      songEmbed.addField("Title:", info.title);
      if (i == array.length - 1) message.channel.send(songEmbed); 
}, 3000);

有一些其他答案指出,有更好的方法来处理此问题,但这应该可以更好地说明此问题。

答案 3 :(得分:0)

由于代码异步运行,因此循环在函数完成之前结束。

您可以使用promise或回调使它保持简单。如果您都不知道,我建议您开始使用回调,并在可以掌握回调时开始使用Promises以及Async和Await。

如何执行此操作的示例是将代码插入到函数中,并以回调作为参数。

function magic_func(array, callback) {
      for (let i = 0; i < array.length; i++) {
        let url = array[i];
        YTDL.getInfo(url, function(err, info) {
          if (err) {
            message.channel.send("There was an error while checking information about a video, try again soon.");
            throw err;
          }
          songEmbed.addField("Title:", info.title);
          if (i == array.length - 1) {
            message.channel.send(songEmbed)
            callback()
          }
        });
      }
}

调用回调后,您可以继续执行下一步,例如:

magic_func(array, function() {
  //ADD your next code here
})

答案 4 :(得分:0)

根据npm examples,getinfo返回一个诺言。 Promise.allArray#mapArray#forEach

的解决方案

Promise.all确保在每个请求完成后将引发then回调。

values代表每个请求array中的info

Promise.all(array.map(url => YTDL.getInfo(url).catch(e => e))
.then(results=>{
  //all the requests have ended
  //add all titles to songEmbed
  results.forEach(result=>{
     if(result instanceof Error){
        console.warn(result.message);
     } else {
       songEmbed.addField("title:", result.title)
     }
  });
  //send songEmbed
  message.channel.send(songEmbed)
}).catch(err=>console.warn(err.message));