Question

I asked a question a couple weeks ago about using setTimeout for a factorial function, but it was unfortunately with an unregistered account and I never got a complete answer.

My main issue is that I'd like to write a function that calculates the factorial of a number but uses the setTimeout or setInterval commands. The impetus behind this is to reset a counter the IE uses so as to avoid a long-running script warning. Currently, the factorial function I have is:

function factorial(n) {
  return 0 === n || 1 === n ? 1 : n * factorial(n - 1)
}

In my other post, jsumners was kind enough to provide me with code that tried to use setTimeout periodically when calculating a factorial:

function factorial(x) {
 executions++;
   if (x > 1) {
      if (executions % 20 === 0) {
          return (function() {
              var y = x;
              setTimeout(function(y) { return y*factorial(y-1); }, 1);
           });
      } else {
        return x*factorial(x-1);
      }
   } else {
  executions = 0;
      return 1;
   }
}

In the above code, it should theoretically use the setTimeout command to perform the next multiplication when the number of elapsed executions is a factor of 20 (mod 20). Unfortunately, the code does not work, and what happens is that if trying to calculate the factorial of a number greater than 20, then the result is NaN. If the number is less than 20, then the answer is correct.

Does anyone know of a solution to this or another way to calculate a factorial by using the setTimeout or setInterval commands?

Thanks!

Was it helpful?

Solution

It's because you're specifying y as a parameter which is undefined when executed because it's not passed in, you can fix it by change this:

setTimeout(function(y) { return y*factorial(y-1); }, 1);

To this:

setTimeout(function() { return y*factorial(y-1); }, 1);

However, it'll still be NaN because here:

      return (function() {
          var y = x;
          setTimeout(function() { return y*factorial(y-1); }, 1);
       });

You're still returning a function, not a number that can be multiplied, so you still can't use a setTimeout() in this manner. You could pass a callback that executes when everything's done, but you can't have it recurse and return to a caller like this.

OTHER TIPS

The callback style factorial with each recurrent step scheduled with setTimeout is:

// private helper function (recurrency with accumulation)
function _factorial(acc, n, callback){
  if(n==0){
    callback(acc);
  }else{
    var callback_wrapper = function(result){
       callback(result);
    };
    setTimeout(function(){_factorial(acc * n, n-1, callback_wrapper)}, 10);
  }
}

// public function
function factorial(n, callback){
  _factorial(1, n, callback);
}

// usage example
factorial(10, function(result){console.log(result)});

-- Cheers, Lambder

http://lambder.com/

http://vanadiumJS.com/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top