如何在js中创建一个好的重复函数

时间:2016-05-25 10:17:11

标签: javascript promise

我试图制作一个后备函数来模仿Promise for ie and whatnot

我有以下代码:

function goPromise(nr){
    console.time("promise");
    var sum = 0;
    var prom = function(){
        return new Promise(function(resolve){
            sum = sum + nr;
            nr = nr-1;
            resolve();
        });
    }
    var doThat = function(){
        if(nr > 0){
            prom().then(function(){
                nr = nr - 1;
                doThat()
            })
        }
        else {
            console.log(sum);
            console.timeEnd("promise");
        }
    }
    doThat();
}

function goNormal(nr){
    console.time("normal");
    var sum = 0;
    var x = function(){
        if(nr > 0){
            sum = sum + nr;
            nr = nr -1;
            x();
        }
        else {
            console.timeEnd("normal")
        }
    }
    x();
}

goNormal比goPromise工作得更好,更快。直到我给它一个像50.000这样的大数字。在这种情况下,它给了我这个

screenshot

无论多少次,它有什么可以做到这一点?

我怎样才能在vanilla js中实现它?

3 个答案:

答案 0 :(得分:0)

承诺是未来的回调,因此它 NOT 递归。这就像使用window.setTimeout(这将解决你在goNormal实例中的问题)。在承诺的情况下,你已经设置了它,因此“doThat”函数的当前执行实际上终止了。

由于涉及承诺,导致将来回调,您会发现它会变慢。您会发现使用setTimeout也会降低执行计划的速度。

给出的例子是设计的,因为不需要递归,但是,我明白你的观点。您是否正在尝试解决这个问题,还是这个学术问题?

使用setTimeout查看下面的示例代码。

function goNormal(nr){
    console.time("normal");
    var sum = 0;
    var x = function(){
        if(nr > 0){
            sum = sum + nr;
            nr = nr -1;
            window.setTimeout(x, 10);
        }
        else {
            console.timeEnd("normal")
        }
    }
    x();
}

答案 1 :(得分:0)

您可以使用requestAnimationFrame再次调用该函数,并再次以大约60fps的间隔再次调用...并使其停止直至满足某个条件。见简单示例:



function recurring() {
  var t1 = performance.now();
  
  if (t1 > 1000) {
    console.log("Done!");
  } else {
    console.log("Still going ... ");
    window.requestAnimationFrame(recurring);
  }
}

window.requestAnimationFrame(recurring);




答案 2 :(得分:0)

This post提供了两个很好的解决方案,允许您执行递归函数,就像它是一个简单的循环一样。

第一个," Trampoline"方法:



function trampoline(cb) {
    while (cb && cb instanceof Function) {
        cb = cb();
    }

    return cb;
};

function goNormalT(nr) {
    console.time("normal");
    var sum = 0;

    var x = function(){
        if(nr > 0){
            sum = sum + nr;
            nr = nr -1;
            return x.bind(null, nr);
        }
        else {
            console.timeEnd("normal");
            return null;
        }
    }

    return trampoline(x.bind(null));
};

goNormalT(50000);




还有第二个,一个" Tail Call Optimizer":



function tco(f) {
  var value;
  var active = false;
  var accumulated = [];

  return function accumulator() {
    accumulated.push(arguments);

    if (!active) {
      active = true;

      while (accumulated.length) {
        value = f.apply(this, accumulated.shift());
      }

      active = false;

      return value;
    }
  }
}

function goNormal(nr) {
  console.time("normal");
  var sum = 0;

  var x = tco(function() {
    if (nr > 0) {
      sum = sum + nr;
      nr = nr - 1;
      return x();
    } else {
      console.timeEnd("normal");
      return null;
    }
  });

  return x();
};

goNormal(50000);




第二个是第一个方法的更复杂的实现。

如果难以掌握这些工作方式,请务必查看文章以获得深入解释。