Как сделать хорошую повторяющуюся функцию в js

Я пытаюсь сделать резервную функцию, которая имитирует обещание для ie и 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();
}

Гонормал работает отлично и быстрее, чем goPromise. Это до тех пор, пока я не дам ему большое число, как 50.000. В этом случае он дает мне это

скриншот

Что такое promise have, что он может делать это независимо от того, сколько раз?

И как я могу реализовать его в vanilla js ?

3 ответа

  1. Обещание-это обратный вызов в будущем, поэтому оно не рекурсивно. Это как использование окна.setTimeout (который решил бы вашу проблему в гонормальном экземпляре). В случае обещания вы настроили его, и, таким образом, текущее выполнение функции «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();
    }
    
  2. Вы можете использовать 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);

  3. Этот пост предлагает два хороших решения, которые позволяют выполнять рекурсивную функцию, как если бы это был простой цикл.

    Первый-метод «батут»:

    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);

    И второй, » хвост оптимизатор вызовов»:

    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);

    Второй — немного более сложная реализация первого метода.

    Если эти способы работы трудно понять, не забудьте проверить статью для глубокого объяснения.