Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using recursive pattern loop with node.js

ive been trying to use node.js to iterate through an array of cities and make an iterative request to google for directions on each (i then JSON.parse to abstract the drive times). I need to find a way to do this synchronously as otherwise i will just be requesting all the info from google on each city at once. I found a good pattern to use at http://tech.richardrodger.com/2011/04/21/node-js-%E2%80%93-how-to-write-a-for-loop-with-callbacks/ but cannot get the callback to work. As you can see, im using a 'show' function to test the same. My code is as follows:

var request = require('request');
var fs = require('fs');
var arr = ['glasgow','preston','blackpool','chorley','newcastle','bolton','paris','york','doncaster'];
//the function I want to call on each city from [arr]
function getTravelTime(a, b,callback){
 request('https://maps.googleapis.com/maps/api/directions/json?origin='+a+'&destination='+b+'&region=en&sensor=false',function(err,res,data){
 var foo = JSON.parse(data);
 var duration = foo.routes[0].legs[0].duration.text;
 console.log(duration);
 });
};

function show(b){
 fs.writeFile('testing.txt',b);
};


function uploader(i){
 if( i < arr.length ){
   show( arr[i],function(){
   uploader(i+1);
   });
 }
}
uploader(0)

The problem I have is that only the first city from the array is output and the callback/iteration never proceeds. Any ideas where im going wrong please?  

like image 690
shane davis Avatar asked Apr 15 '12 12:04

shane davis


2 Answers

Thanks for the pointers, was clearly down to my poor understanding of callbacks in javascript. Just reading JavaScript patterns by O'Reilly and hit the 'Callback pattern' sections - doh!

For anyone who doesn't know, this is how the code will work:

var arr = ['glasgow','preston','blackpool','chorley','newcastle','bolton','paris','york','doncaster'];

function show(a,callback){
    console.log(a);
    callback();
}

function uploader(i){
  if( i < arr.length ){
    show(arr[i],
         function(){
          uploader(i+1)
         });
   };
}
uploader(0) 
like image 175
shane davis Avatar answered Sep 28 '22 13:09

shane davis


I was also facing issues like this, so I've written a recursive callback function which will act as a for loop but you can control when to increment. The following is that module, name as syncFor.js and include this in your program

module.exports = function syncFor(index, len, status, func) {
    func(index, status, function (res) {
        if (res == "next") {
            index++;
            if (index < len) {
                syncFor(index, len, "r", func);
            } else {
                return func(index, "done", function () {
                })
            }
        }
    });
}

//this will be your program if u include this module
var request = require('request');
var fs = require('fs');
var arr = ['glasgow', 'preston', 'blackpool', 'chorley', 'newcastle', 'bolton', 'paris', 'york', 'doncaster'];
var syncFor = require('./syncFor'); //syncFor.js is stored in same directory
//the following is how u implement it

syncFor(0, arr.length, "start", function (i, status, call) {
    if (status === "done")
        console.log("array iteration is done")
    else
        getTravelTime(arr[i], "whatever", function () {
            call('next') // this acts as increment (i++)
        })
})


function getTravelTime(a, b, callback) {
    request('https://maps.googleapis.com/maps/api/directions/json?origin=' + a + '&destination=' + b + '&region=en&sensor=false', function (err, res, data) {
        var foo = JSON.parse(data);
        var duration = foo.routes[0].legs[0].duration.text;
        callback(); // call the callback when u get answer
        console.log(duration);
    });
};
like image 23
subbu Avatar answered Sep 28 '22 13:09

subbu