小编典典

对于未使用递延[anti]模式创建的承诺的承诺

javascript

问题1:在给定的时间只允许一个API请求,因此,真正的网络请求在尚未完成的情况下排队。应用可以随时调用API级别,并且期望得到回报。当API调用排入队列时,将在将来的某个时刻创建对网络请求的承诺-
返回什么给应用程序?这样可以通过延迟的“代理”承诺来解决:

var queue = [];
function callAPI (params) {
  if (API_available) {
    API_available = false;
    return doRealNetRequest(params).then(function(data){
      API_available = true;
      continueRequests();
      return data;
    });
  } else {
    var deferred = Promise.defer();
    function makeRequest() {
      API_available = false;
      doRealNetRequest(params).then(function(data) {
        deferred.resolve(data);
        API_available = true;
        continueRequests();
      }, deferred.reject);
    }
    queue.push(makeRequest);
    return deferred.promise;
  }
}

function continueRequests() {
  if (queue.length) {
    var makeRequest = queue.shift();
    makeRequest();
  }
}

问题2:对一些API调用进行反跳动,以便随着时间的推移累积要发送的数据,然后在达到超时时分批发送。调用API的应用期望得到回报。

var queue = null;
var timeout = 0;
function callAPI2(data) {
  if (!queue) {
    queue = {data: [], deferred: Promise.defer()};
  }
  queue.data.push(data);
  clearTimeout(timeout);
  timeout = setTimeout(processData, 10);
  return queue.deferred.promise;
}

function processData() {
  callAPI(queue.data).then(queue.deferred.resolve, queue.deferred.reject);
  queue = null;
}

阅读 273

收藏
2020-05-01

共1个答案

小编典典

对尚未建立的承诺的承诺

…很容易通过将then调用与创建承诺的回调链接起来来构建,以保证将来可以创建承诺。

如果您承诺一个承诺,则 永远不要 使用延迟模式。Promise当且仅当您要等待异步且 尚未涉及promise
时,才应使用deferreds或构造函数。在所有其他情况下,您应该撰写多个承诺。

当你说

当API调用排入队列时,将在将来的某个时刻创建对网络请求的承诺

那么您不应该创建一个延后的协议,以便在创建承诺后就可以稍后解决(或者更糟的是,一旦实现承诺,就可以用承诺结果来解决它),而应该在将来的某个时刻获得承诺网络要求将完成。基本上你要写

return waitForEndOfQueue().then(makeNetworkRequest);

当然,我们将需要分别更改队列。

var queue_ready = Promise.resolve(true);
function callAPI(params) {
  var result = queue_ready.then(function(API_available) {
    return doRealNetRequest(params);
  });
  queue_ready = result.then(function() {
    return true;
  });
  return result;
}

这具有额外的好处,您将需要显式处理队列中的错误。在这里,一旦一个请求失败(您可能想要更改它),每个调用都会返回一个被拒绝的承诺-
在您的原始代码中,queue刚被卡住(您可能没有注意到)。

第二种情况稍微复杂一些,因为它确实涉及到setTimeout调用。这是一个异步原语,我们需要手动为其构建承诺-
但仅用于超时,而没有其他目的。再次,我们将获得超时的承诺,然后只需将我们的API调用链接到该请求即可获得我们想要返回的承诺。

function TimeoutQueue(timeout) {
  var data = [], timer = 0;
  this.promise = new Promise(resolve => {
    this.renew = () => {
      clearTimeout(timer);
      timer = setTimeout(resolve, timeout);
    };
  }).then(() => {
    this.constructor(timeout); // re-initialise
    return data;
  });
  this.add = (datum) => {
    data.push(datum);
    this.renew();
    return this.promise;
  };
}

var queue = new TimeoutQueue(10);
function callAPI2(data) {
  return queue.add(data).then(callAPI);
}

您可以在此处看到:a)如何完全消除抖动的逻辑callAPI2(可能没有必要,但有一点很重要),以及b)promise构造函数如何仅与超时有关,而没有其他问题。它甚至不需要resolve像延迟的那样“泄漏”该功能,它唯一可用于外部的就是renew允许扩展计时器的功能。

2020-05-01