javascript - NodeJS - how to make forEach and for loop functions sequential - Stack Overflow

server.queue.forEach(function(q) {YTDL.getInfo(q, (error, info) => {console.log(info["title&quo

server.queue.forEach(function(q) {
    YTDL.getInfo(q, (error, info) => {
        console.log(info["title"]);
        message.reply('"' + info["title"] + '"');
    });
});

for (var i = 0; i < server.queue.length; i++) {
    YTDL.getInfo(server.queue[i], (error, info) => {
         console.log(info["title"]);
         message.reply('"' + info["title"] + '"');
    });
}

I'm creating a music bot for a VoIP called Discord using Node.js and whenever either of the loops above execute, they print in a random order. How do I make it so that they are printed sequentially (server.queue[0], server.queue[1], server.queue[2]...)? YTDL is a package called ytdl-core that downloads YouTube videos as well as display the info such as the title of a video using the video link. server.queue is an array of YouTube video links.

server.queue.forEach(function(q) {
    YTDL.getInfo(q, (error, info) => {
        console.log(info["title"]);
        message.reply('"' + info["title"] + '"');
    });
});

for (var i = 0; i < server.queue.length; i++) {
    YTDL.getInfo(server.queue[i], (error, info) => {
         console.log(info["title"]);
         message.reply('"' + info["title"] + '"');
    });
}

I'm creating a music bot for a VoIP called Discord using Node.js and whenever either of the loops above execute, they print in a random order. How do I make it so that they are printed sequentially (server.queue[0], server.queue[1], server.queue[2]...)? YTDL is a package called ytdl-core that downloads YouTube videos as well as display the info such as the title of a video using the video link. server.queue is an array of YouTube video links.

Share Improve this question asked Aug 11, 2017 at 22:19 user3439521user3439521
Add a ment  | 

3 Answers 3

Reset to default 2

Just to add why you try to make it sequential: YouTube has rate limits and etc limitations which can be easily broken if there will be parallel calls.

So for that reason we are not using Promise.all or .allSettled.

Solution to question based on modules and language features of stack for the year 2017:

  1. install: npm i --save async

  2. and the code:

const async = require('async');
    
async.eachSeries(
  server.queue,
  (q, next) => {
    YTDL.getInfo(q, (error, info) => {
        console.log(info["title"]);
        message.reply('"' + info["title"] + '"');
        next();
    });
  }
});

for..loop is not good solution for asynchronous stuff - it will call them and run next statements that es after for loop.


Question is dated for the year 2017, for that moment there was no proper support of async/await methods and etc. Plus people were staying at LTS versions of Node.js which slowed down progress.

If you don't want to use the async library, you can use Promise.all like this

const youtubeData = [];
for (var i = 0; i < server.queue.length; i++) {
  youtubeData.push(YTDL.getInfo(server.queue[i]));
}

Promise.all(youtubeData).then((values) => {
  // These values will be in the order in which they are called.
});

Note that Promise.all will wait for all the queries to finish or reject everything whenever one request fails. Look at your use case and select accordingly.

As per library, it returns promise if no callback is provided

ytdl.getInfo(url, [options], [callback(err, info)])

Use this if you only want to get metainfo from a video. If callback isn't given, returns a promise.

I was struggling with this problem for a while to find the best solution until I found out the built-in yield feature represented in ECMA6. so using gen-run library you can do the following:

let run = require('gen-run');

function notSequential(){
    for (let i = 0; i < 3; i++)
        f(i * 1000);
    console.log("it won't print after for loop");
}

function sequential(){
    run(function*(){
        for (let i = 0; i < 3; i++)
            yield changedF(i * 1000);
        console.log("it will print after for loop");
    });
}

function f(time) {
    setTimeout(function(){
        console.log(time);
    }, time);
}

function changedF(time) {
    return function (callback) {
        setTimeout(function(){
            console.log(time);
            callback();
        }, time);
    }
}

notSequential();

it won't print after for loop 0 1000 2000

sequential();

0 1000 2000 it will print after for loop

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745187321a4615698.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信