静下心来的个人专栏
上一篇

Promise.any()方法

广告
选中文字可对指定文章内容进行评论啦,→和←可快速切换按钮,绿色背景文字可以点击查看评论额。
大纲

Promise.any()方法

Promise.any() 方法还接受一个可迭代的Promises,并在任何传入的 Promise 实现时返回一个fulfilled的 Promise。一旦Promise之一fulfilled,操作就会短路。 (这与 Promise.all() 正好相反,一旦一个 Promise rejected,操作就会短路。)下面是一个例子:

let promise1 = Promise.reject(43);

let promise2 = Promise.resolve(42);

let promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(44);
  }, 100);
});

let promise4 = Promise.any([promise1, promise2, promise3]);

promise4.then(value => console.log(value));

即使此示例中的第一个promise (promise1) 被拒绝,对 Promise.any() 的调用也会成功,因为第二个promise (promise2)已实现。 第三个promise(promise3)的结果被丢弃。

如果传递给 Promise.any() 的所有 Promise 都被拒绝,则返回的 Promise 会被 AggregateError 拒绝。 AggregateError 是一个错误,表示存储在 anerrors 属性中的多个错误。 例如:

let promise1 = Promise.reject(43);

let promise2 = new Promise((resolve, reject) => {
  reject(44);
});

let promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(45);
  }, 100);
});

let promise4 = Promise.any([promise1, promise2, promise3]);

promise4.catch(reason => {
  // Runtime dependent error message
  console.log(reason.message);

  // output rejection values
  console.log(reason.errors[0]); // 43
  console.log(reason.errors[1]); // 44
  console.log(reason.errors[2]); // 45
});

在这里,Promise.any() 接收到not fulfilled的 Promise,因此返回的 Promise 被 AggregateError 拒绝。 您可以检查 errors 属性,它是一个数组,以从每个 Promise 中检索rejection value。

 

Promise.any()使用场景

Promise.any() 方法最适用于您希望任何一个 Promise完成但是不在意有多少其他拒绝的情况,除非他们都拒绝。一下是一些使用场景

执行对冲请求

正如 The Tail at Scale² 中所定义的,对冲请求是客户端向多个服务器发出请求并接受来自第一个回复的响应的请求。 这在客户端需要尽可能低的延迟并且有专门用于管理额外负载和重复数据删除响应的服务器资源的情况下很有帮助。 这是一个例子:

const HOSTS = [
  "api1.example.com",
  "api2.example.com"
];

function hedgedFetch(endpoint) {
  return Promise.any(
    HOSTS.map(hostname => fetch(`https://${hostname}${endpoint}`))
  );
}

hedgedFetch("/transactions")
  .then(transactions => console.log(transations))
  .catch(reason => console.error(reason.message));

此示例保留了为每个对冲请求调用的主机数组。hedgedFetch() 函数根据这些主机名创建一个 fetch() 请求数组并传递该数组到 Promise.any()。 对于hedgedFetch() 的使用者来说,看起来好像只发出了一个请求,即使在幕后发生了多个请求。 这允许消费者仅使用一个fulfillment handler和一个rejection handler来处理结果。 如果任何一个请求失败,消费者永远不会知道; 只有当所有请求都失败时才会调用rejection hanlder。

 

在 Service Worker 中使用最快的响应

使用Service Worker的网页通常可以选择从何处加载数据:网络或缓存。 在某些情况下,网络请求实际上可能比从缓存加载更快,因此您可能希望使用 Promise.any() 来选择更快的响应。 下面的一些代码说明了 service worker 内部的这种模式:

self.addEventListener("fetch", event => {

	// get cached response
	const cachedResponse = caches.match(event.request);

	// fetch new response
	const fetchedResponse = fetch(event.request.url);

	// respond with the best option
	event.respondWith(
	  Promise.any([
	   fetchedResponse.catch(() => cachedResponse),
	   cachedResponse,
	   ])
	  .then(response => response ?? fetchedResponse)
	  .catch(() => {})
	);
});

fetch 事件侦听器允许您侦听网络请求并拦截响应。 此service worker示例使用 fetch 事件侦听器从缓存(使用 caches.match())和网络(使用 fetch())读取。 对 caches.match() 的调用会返回一个始终满足的promise,无论是使用匹配的响应对象,还是使用未定义的请求(如果请求不在缓存中)。 event.respondWith() 方法期望传递一个 Promise,因此这个事件处理程序传递 Promise.any() 的结果。

两个 Promise 被传递给 Promise.any():带有rejection handler的获取响应,默认返回缓存响应本身。 这样,缓存的响应如果存在且命中以及获取的响应rejected,则返回缓存响应。 然后,实现处理程序确保有一个有效的响应(请记住,如果缓存响应未命中,则响应可能是未定义的)。 拒绝处理程序不做任何事情,因为在这种情况下没有回退。 获取的响应和缓存的响应都被拒绝了,因此错误被静默忽略以允许浏览器使用其默认行为。

虽然 Promise.any() 在第一个fulfilled的promise后短路,但您可能还希望根据第一个settled的promise短路操作,而不管结果如何。

版权声明:著作权归作者所有。

X

欢迎加群学习交流

联系我们