当前位置: 首页 > 面试题库 >

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

盛辰沛
2023-03-14
问题内容

问题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;
}

问题答案:

对尚未建立的承诺的承诺

…很容易通过将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允许扩展计时器的功能。



 类似资料:
  • 问题内容: 我有一个整数id的数组,例如 并且我需要为每个ID执行异步远程调用。每个调用都是一个使用$ resource执行的WebAPI请求,并显示为Promise。 我需要创建一个接受这些ID数组的函数,然后初始化递归承诺链。该链应导致对每个ID依次进行webapi调用。这些调用不应并行,而应链接在一起。 有问题的函数返回自己一个“主要”的承诺,该承诺应根据异步Web调用的结果来解决或拒绝。也

  • 问题内容: 我想遍历HTML 5文件系统中的所有文件,并在迭代完成后开始一些事件。由于这是异步+承诺,我很难尝试掌握其工作方式。 我正在使用angularJS,并创建了一个服务来封装html 5文件系统特定的功能。 这是递归函数: 理想情况下,我想这样调用该函数,并让其返回一个承诺,一旦遍历所有文件,该承诺便会执行。 有什么技巧/想法可以实现吗? 一个想法是拥有一个诺言数组,并为每个文件/目录向该

  • 问题内容: 我想做这样的事情: 因此,我想声明一个承诺,可以使用then来解决。但是,此承诺可能会被另一个返回内容的承诺覆盖。以后我想解决诺言是否有内容。这可能吗?我尝试过: 但是,当用户在场时这不起作用。有任何想法吗? 问题答案: 就像Bixi所写的那样,您可以使用将承诺或价值包装到承诺中。如果您传递给的是承诺,则将返回该承诺,否则将创建一个新的承诺,并直接使用您传递的值来解决。类似以下内容:

  • 问题内容: 这是一些基于行为的简单问题,我在下面的示例中在节点上运行时注意到了这些行为: 输出为: 1)为什么要实现在立即对已知值运行回调之前等待?为什么不够智能,以至于第一行在第二行运行之前同步发布其输出? 2)什么是之间的时间流逝和被输出?它是单个进程滴答吗? 3)能否将绩效深深包裹在承诺中而产生绩效问题?例如,即使可以有效地同步解决,它是否也要异步等待3倍的时间才能完成? 问题答案: 这实际

  • 问题内容: 编辑 继续重试直到承诺解决的模式(带有delay和maxRetries)。 在结果满足条件之前一直重试的模式(带有delay和maxRetries)。 具有无限重试次数(提供延迟)的高效内存动态模式。 #1的代码。 继续重试,直到承诺解决为止(该语言是否有任何改进社区?) 采用 #2的代码会 继续重试,直到条件以可重用的方式满足条件为止(条件会有所不同)。 问题答案: 有点不同… 异步

  • 问题内容: wifiservice.js: 我的整个控制器: 我想做的是调用$ scope.getList(),它返回周围wifi SSID的列表,然后在$ scope.checkin()中,我要处理这些数据。 由于扫描需要一些时间,因此我必须等待getList函数完成,这就是为什么我尝试使用.then的原因,但这给了我标题上的错误提示。有任何想法吗? 问题答案: 好吧,我想出了一些不同的东西: