12

Say if I have a structure in Node.js shown below:

for (i = 0; i < 50; i++) {
    //Doing a for loop.
}

function after_forloop() {
    //Doing a function.
}

after_forloop();

So how could I make sure the after_forloop() function is fired after the forloop is completed?

In case if you want to see what I am actually working on:

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

var proxyChecker = require('proxy-checker');
var fs = require('fs');

function get_line(filename, line_no, callback) {
    fs.readFile(filename, function (err, data) {
        if (err) throw err;
        var lines = data.toString('utf-8').split("\n");
        var firstLineBreak = data.toString('utf-8').indexOf("\n");
        var originalText = data.toString('utf-8');
        var newText = originalText.substr(firstLineBreak + 1);
        if(+line_no > lines.length){
            return callback('File end reached without finding line', null);
        }

        callback(null, lines[+line_no], newText);
    });
}


for (i = 0; i < 50; i++) {
    get_line('proxy_full.txt', i, function(err, line, newText){
        fs.appendFile('proxy.txt', line + '\n', function (err) {
            if (err) throw err;         
        });     
        fs.writeFile('proxy_full.txt', newText, function (err) {
            if (err) throw err;
        });
    })
}

after_forloop();

function after_forloop() {
    proxyChecker.checkProxiesFromFile(
        // The path to the file containing proxies
        'proxy.txt',
        {
            // the complete URL to check the proxy
            url: 'http://google.com',   
            // an optional regex to check for the presence of some text on the page
            regex: /.*/
        },
        // Callback function to be called after the check
        function(host, port, ok, statusCode, err) {
            if (ok) {
                console.log(host + ':' + port);
                fs.appendFile('WorkingProxy.txt', host + ':' + port + '\n', function (err) {
                    if (err) throw err;             
                });
            }                   
        }
    );

    setTimeout(function(){
        fs.writeFile('proxy.txt', "", function (err) {
            if (err) throw err;
        });
        console.log('Proxy Check Completed.')
        process.exit(1); 
    }, 5000);
}

Basically I like to allow the node server run 50 test on a list proxy servers at a time (within five seconds). And then the server should save the working proxies to a new file.

Aero Wang
  • 8,382
  • 14
  • 63
  • 99
  • Execute it after the loop? Note you forgot to declare `i`. – elclanrs Jan 13 '15 at 02:51
  • 9
    By "after the `for` loop is completed" you probably mean "after all the asynchronous activity started in the `for` loop is completed", right? – Pointy Jan 13 '15 at 02:51
  • I'm not getting what special here, just call that after `for` loop finished. – Mritunjay Jan 13 '15 at 02:51
  • code usually runs top-down, but if it's not, you can make sure _i_ is 50... – dandavis Jan 13 '15 at 02:55
  • can you show the content of `for` loop. – Mritunjay Jan 13 '15 at 02:57
  • Not quite sure exactly what you are asking here, but in async cases sometimes these are useful for avoiding "*callback hell*": https://github.com/caolan/async -- http://stackoverflow.com/a/21184964/103081 – Paul Jan 13 '15 at 03:08
  • just post full code, as you have mentioned in comments at answer, writing to file is a `async` task if you are not using a `sync` function. That's why you are facing strange behaviour. – Mritunjay Jan 13 '15 at 03:09
  • @Mritunjay I just did! :) – Aero Wang Jan 13 '15 at 03:15

6 Answers6

10

Maybe this helps:

var operationsCompleted = 0;
function operation() {
    ++operationsCompleted;
    if (operationsCompleted === 100) after_forloop(); 
}
for (var i = 0; i < 50; i++) {
    get_line('proxy_full.txt', i, function(err, line, newText){
        fs.appendFile('proxy.txt', line + '\n', function (err) {
            if (err) throw err;
            operation();
        });     
        fs.writeFile('proxy_full.txt', newText, function (err) {
            if (err) throw err;
            operation();
        });
    })
}

Admittedly this isn't an elegant solution. If you're doing a whole lot of this you might want to check out something like Async.js.

Ethan Lynn
  • 1,009
  • 6
  • 13
9

If you're doing any async operation in the for loop, you can simply keep it like

function after_forloop() {
// task you want to do after for loop finishes it's execution
}


 for (i = 0; i < 50; i++) {
 //Doing a for loop.

 if(i == 49) {
  after_forloop() // call the related function
 }
}

Still in node.js, instead of making use of for loops with asynchronous functions, you should see the async module. Here's Async.js or you can consider using recursion too.

Parth Vyas
  • 487
  • 4
  • 16
7

If there is no magic happening then it should be straight forword.

Function:-

function after_forloop() {
    //Doing a function.
}

For Loop:-

for (i = 0; i < 50; i++) {
    //Doing a for loop.
}
for (i = 0; i < 50; i++) {
    //Doing another for loop.
}
after_forloop();

This will call after_forloop just after both for loops finishes. Because for loop is a blocking call, calling of after_forloop() has to wait.

Note:- If you are doing some async task in for loops then the function will be called after loop finished, but the work you are doing in loops might not finished by the time of calling function.

Mritunjay
  • 25,338
  • 7
  • 55
  • 68
  • Great! What happen if I have multiple for loops, will it wait for all the for loops to complete? – Aero Wang Jan 13 '15 at 02:57
  • @AeroWindwalker Yes the line will be called after `for` loop finished, because `for` loop is a sync task, it will blocking. – Mritunjay Jan 13 '15 at 02:58
  • I think Nodejs isn't letting for loop running as a sync task. For example if I let the for loop to create a file with 50 lines, then having a function output the file, it will only output 1 or 2 lines (sometimes no line at all). – Aero Wang Jan 13 '15 at 03:04
  • @AeroWindwalker you should probably forgot to read the `note` part of answer. I told you if you are doing some `async` task in `for` loop that might not finished. – Mritunjay Jan 13 '15 at 03:07
  • Interesting! What would be the solution to it if I am doing asyn tasks in the forloop? – Aero Wang Jan 13 '15 at 03:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/68696/discussion-between-aero-windwalker-and-mritunjay). – Aero Wang Jan 13 '15 at 03:12
4

You can handle the last iteration of the for loop with a conditional checking index.

for(let i = 0; i < 10; i++){
  if(i == 10 - 1){
    your_function();
  }
}
sonEtLumiere
  • 4,461
  • 3
  • 8
  • 35
2

use the Async module, Its easy and best.

async.each(array, function (element, callback) {
                        callback()
                    }, async function (err) {
                       console.log("array ends")
                    });
Amit Rana
  • 33
  • 7
0

Simplest one!

try {
  for (i = 0; i < 50; i++) {
    //Doing a for loop.
  }
} finally {
  after_forloop();
}
Rohit Nishad
  • 2,570
  • 2
  • 22
  • 32