jQuery递归的Promise函数有什么问题?

What is wrong with this recursive Promise function with jQuery Deferred

本文关键字:什么 问题 函数 递归 Promise jQuery      更新时间:2023-09-26

我正在编写ReST API流程的脚本。现在我需要一个函数,它保持重试请求尽可能多的API在几秒钟内。

所以我写了一些承诺的抽象,我做了如下的东西:

$(function () {
  var $el = $('#test');
  function api (message) {
    return $.ajax('/echo/json/', {
      method: 'POST',
      data: { json: JSON.stringify({ message: message }), delay: 2000 },
      timeout: 1000
    });
  }
  // Process to keep retrying an API request as many as possible in 3 seconds
  retried(_.bind(api, undefined, 'Hello, world.'), 3000)
  .then(function (dat) {
    $el.text(dat.message);
  }, function (err) {
    if (err instanceof Error) $el.css('color', 'red');
    $el.text(err.message);
  });
});

我为上面写的一些函数如下:

// Promise wrapper
var promisify = function (func) {
  var funcPartial = function () {
    var funcArgs = _.toArray(arguments);
    var dfr = new $.Deferred(), promiseArgs = [ dfr.resolve, dfr.reject ];
    var timeoutId = setTimeout(function () {
      clearTimeout(timeoutId);
      func.apply(undefined, _.union(promiseArgs, funcArgs));
    }, 1);
    return dfr.promise();
  };
  return funcPartial;
};
// Promise abstraction for recursive call
retried = promisify(function (resolve, reject, done, duration, start) {
  if (!_.isNumber(start)) start = +(new Date());
  return done()
  .then(resolve, function (err) {
    var stop = +(new Date());
    if (duration <= stop - start) {
      reject(err);
    } else {
      return retried(done, duration, start);
    }
  });
});

进程在正确的条件下完成,但是retried函数没有返回Promise链。

我真的很累。有人能指出我错误的点来纠正上面的实现吗?

这是整个演示脚本

谢谢。

感谢下面的@BenjaminGruenbaum,我刚刚注意到我根本不需要promisify来使retried起作用。这是一个完全可耻的问题,但再次感谢所有回答这个问题的人。

这是修改后的retried函数,根本不需要promisify

var retried = function (done, duration, start) {
  if (!_.isNumber(start)) start = +(new Date());
  return done()
  .then(function (dat) {
    return dat;
  }, function (err) {
    var stop = +(new Date());
    if (duration > stop - start) return retried(done, duration, start);
    return err;
  });
};

我更新了演示,它现在工作正常XD

演示(修订)

您的重试逻辑非常复杂。您正在"承诺"一个具有解析和拒绝并执行显式构造的函数。如何在同步代码中实现重试?

do {
   var failed = false;
   try { 
       var val = fn();
   } catch(e){
       failed = true;
   }
} while(failed);

但是我们不能这样做,因为我们不能使用循环,但是我们可以用递归来代替:

function retry(fn){
    try {
       return fn(); // call the function
    } catch(e){
       return retry(fn); // retry it again
    }
}

现在,添加承诺只是意味着失败不是由于try/catch,而是由于承诺的解决/缺乏:

function retry(fn) {
    return fn().then(null, function(e){ 
        return retry(fn); // on failure handler, retry again.
    });
}

这个实现的好处是不依赖于所使用的承诺库(它将使用与fn返回的类型相同的类型)。

作为旁注,请不要忽略错误。即使是网络错误-至少在某个地方记录它们:)