Search code examples
javascriptrecursionstackintern

How to call this function recursively?


I'm trying to come up with basic web crawler. The stack keeps track of all the URLs to visit in future.

Until the stack gets empty, want to get list of all hrefs used within a web page. Tried to use arguments.calee but it returns:

RangeError: Maximum call stack size exceeded

JavaScript

"checkStack": function(test) {
    //check if the stack is empty
    if (!stack.isEmpty()) {
        var newAddress = stack.pop();
        console.log("trying to navigate to: ", newAddress);
        return test.remote.get(newAddress)
            .setFindTimeout(240000)
            //.sleep(4000)
            .findAllByTagName("a")
            .getAttribute("href")
            .then(function(hrefs) {
                console.log("got hrefs: " + hrefs.length);
                assert.isArray(hrefs, 'Links not an array');
                checkAddressValidity(hrefs, 0);
            })
            .then(function() {
                //call checkStack recursively
                checkStack(test);
            }.bind(test));

    }
},
...

Solution

  • The easy way to perform recursion in a Command chain (or any Promise chain, actually!) is to hold your stack in closure, then call the method that does the work recursively as a Promise callback until your stack is exhausted. Once the stack is resolved undefined will be returned by next instead of another promise, which signals the end of the recursion:

    checkStack: function (test) {
      var remote = test.remote;
      var stack = [];
    
      function next() {
        var newAddress = stack.pop();
        if (newAddress) {
          return remote.get(newAddress)
            .findAllByTagName('a')
            .getAttribute('href')
            .then(function (hrefs) {
              // do whatever
            })
            .then(next);
        }
      }
    
      return next();
    }