所以我有这段代码:
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()内部将正确的元素索引传递给此函数,希望您能理解我。
答案 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.all,Array#map和Array#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));