乐趣区

关于前端:如何使用Promiserace-和-Promiseany

作者:Mahdhi Rezvi
译者:前端小智
起源: medium

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

自 1996 年公布以来,JS 始终在稳步改良。随着 ECMAScript 版本的许多改良,最近的版本是ES2020。JS 的一个重要更新是Promise,在 2015 年, 它以 ES6 的名义公布。

什么是 Promise?

MDN 上对 Promise 的定义:Promise 对象用于示意一个异步操作的最终实现 (或失败)及其后果值。对于老手来说,这听起来可能有点太简单了。

国外一位大什么对 Promises 的解释如下:“设想一下你是个孩子。你老妈向你保障,她下周会给你买一部新手机。”

你要到下周能力晓得你是否能获取那部手机。你老妈要么真的给你买了一个全新的手机,要么因为不开心就不给你买。

这个就是一个 Promise。一个Promise 有三个状态。别离是:

  1. Pending:你不晓得你是否能失去那部手机
  2. Fulfilled:老妈快乐了,给你买了
  3. Rejected:老娘不开森了,不给你买了

这个是我目前听到,最快能了解 Promise 事例。

如果你还没有开始学习 Promise,倡议你这样做。

Promise 蕴含几种十分有用的内置办法。明天咱们次要介绍这两种办法。

  • Promise.race()- 与 ES6 一起公布
  • Promise.any() - 仍处于第 4 阶段的提案中

Promise.race()

Promise.race()办法最后是在 ES6 中引入 Promise 时公布的,这个办法须要一个 iterable 作为参数。

Promise.race(iterable) 办法返回一个 promise,一旦迭代器中的某个 promise 解决或回绝,返回的 promise 就会解决或回绝。

Promise.any() 办法不同,Promise.race()办法次要关注 Promise 是否已解决,而不论其被解决还是被回绝。

语法

Promise.race(iterable)

参数

iterable — 可迭代对象,相似 Array。iterable 对象实现 Symbol.iterator 办法。

返回值

一个 待定的 Promise 只有给定的迭代中的一个 promise 解决或回绝,就采纳第一个 promise 的值作为它的值,从而 异步 地解析或回绝(一旦堆栈为空)。

留神

因为参数承受 iterable,所以咱们能够传递一些值,比方根本值,甚至数组中的对象。在这种状况下,race 办法将返回传递的第一个非 promise 对象。这次要是因为办法的行为是在值可用时 (当 promise 满足时) 立刻返回值。

此外,如果在 iterable 中传递了曾经解决的 Promise,则 Promise.race() 办法将解析为该值的第一个。如果传递了一个空的 Iterable,则race 办法将永远处于待处理状态。

事例

const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'promise 1 resolved');
});

const promise2 = new Promise((resolve, reject) => {setTimeout(reject, 100, 'promise 2 rejected');
});

const promise3 = new Promise((resolve, reject) => {setTimeout(resolve, 200, 'promise 3 resolved')
});

(async () => {
    try {let result = await Promise.race([promise1, promise2, promise3]);
        console.log(result);
    } catch (err) {console.error(err);
    }
})();
  // 输入 - "promise 2 rejected"
  // 只管 promise1 和 promise3 能够解决,但 promise2 回绝的速度比它们快。// 因而 Promise.race 办法将以 promise2 回绝

实在用例

当初,你可能想晓得,咱们在实战中何时 Promise.race()?来看看。

在申请数据时,显示加载动画

应用加载动画开发中是十分常见。当数据响应工夫较长时,如果没应用加载动画,看起来就像没有响应一样。但有时,响应太快了,咱们须要加载动画时,减少一个十分小延迟时间,这样会让用户感觉我是在常常申请过去的。要实现这一点,只需应用 Promise.race() 办法,如下所示。


function getUserInfo(user) {return new Promise((resolve, reject) => {
    // had it at 1500 to be more true-to-life, but 900 is better for testing
    setTimeout(() => resolve("user data!"), Math.floor(900*Math.random()));
  });
}

function showUserInfo(user) {return getUserInfo().then(info => {console.log("user info:", info);
    return true;
  });
}

function showSpinner() {console.log("please wait...")
}

function timeout(delay, result) {
  return new Promise(resolve => {setTimeout(() => resolve(result), delay);
  });
}
Promise.race([showUserInfo(), timeout(300)]).then(displayed => {if (!displayed) showSpinner();});

勾销的 Promise

有些状况下,咱们须要勾销 Promise,这时也能够借助 Promise.race() 办法:

function timeout(delay) {
  let cancel;
  const wait = new Promise(resolve => {const timer = setTimeout(() => resolve(false), delay);
    cancel = () => {clearTimeout(timer);
      resolve(true);
    };
  });
  wait.cancel = cancel;
  return wait;
}


function doWork() {const workFactor = Math.floor(600*Math.random());
  const work = timeout(workFactor);
  
  const result = work.then(canceled => {if (canceled)
      console.log('Work canceled');
    else
      console.log('Work done in', workFactor, 'ms');
    return !canceled;
  });
  result.cancel = work.cancel;
  return result;
}

function attemptWork() {const work = doWork();
  return Promise.race([work, timeout(300)])
    .then(done => {if (!done)
        work.cancel();
      return (done ? 'Work complete!' : 'I gave up');
  });
}

attemptWork().then(console.log);

批处理申请,用于长时间执行

Chris Jensen 有一个乏味的 race() 办法用例。他曾应用 Promise.race() 办法批处理长时间运行的申请。这样一来,他们能够放弃并行申请的数量固定。

const _ = require('lodash')

async function batchRequests(options) {let query = { offset: 0, limit: options.limit};

    do {batch = await model.findAll(query);
        query.offset += options.limit;

        if (batch.length) {const promise = doLongRequestForBatch(batch).then(() => {
                // Once complete, pop this promise from our array
                // so that we know we can add another batch in its place
                _.remove(promises, p => p === promise);
            });
            promises.push(promise);

            // Once we hit our concurrency limit, wait for at least one promise to
            // resolve before continuing to batch off requests
            if (promises.length >= options.concurrentBatches) {await Promise.race(promises);
            }
        }
    } while (batch.length);

    // Wait for remaining batches to finish
    return Promise.all(promises);
}

batchRequests({limit: 100, concurrentBatches: 5});

Promise.any()

Promise.any() 接管一个 Promise 可迭代对象,只有其中的一个 promise 胜利,就返回那个曾经胜利的 promise。如果可迭代对象中没有一个 promise 胜利(即所有的 promises 都失败 / 回绝),就返回一个失败的 promise 和 AggregateError 类型的实例,它是 Error 的一个子类,用于把繁多的谬误汇合在一起。实质上,这个办法和 Promise.all() 是相同的。

留神!Promise.any() 办法仍然是实验性的,尚未被所有的浏览器齐全反对。它以后处于 TC39 第四阶段草案(Stage 4)

语法

Promise.any(iterable);

参数

iterable — 个可迭代的对象, 例如 Array。

返回值

  • 如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise
  • 如果传入的参数不蕴含任何 promise,则返回一个 异步实现(asynchronously resolved)的 Promise。
  • 其余状况下都会返回一个 解决中(pending) 的 Promise。只有传入的迭代对象中的任何一个 promise 变成胜利(resolve)状态,或者其中的所有的 promises 都失败,那么返回的 promise 就会 异步地(当调用栈为空时)变成胜利 / 失败(resolved/reject)状态。

阐明

这个办法用于返回第一个胜利的 promise。只有有一个 promise 胜利此办法就会终止,它不会期待其余的 promise 全副实现。

不像 Promise.all() 会返回一组实现值那样(resolved values),咱们只能失去一个胜利值(假如至多有一个 promise 实现)。当咱们只须要一个 promise 胜利,而不关怀是哪一个胜利时此办法很有用的。

同时, 也不像 Promise.race() 总是返回第一个后果值(resolved/reject)那样,这个办法返回的是第一个 胜利的 值。这个办法将会疏忽掉所有被回绝的 promise,直到第一个 promise 胜利。

事例

const promise1 = new Promise((resolve, reject) => {setTimeout(reject, 100, 'promise 1 rejected');
});

const promise2 = new Promise((resolve, reject) => {setTimeout(resolve, 400, 'promise 2 resolved at 400 ms');
});

const promise3 = new Promise((resolve, reject) => {setTimeout(resolve, 700, 'promise 3 resolved at 800 ms');
});

(async () => {
  try {let value = await Promise.any([promise1, promise2, promise3]);
    console.log(value);
  } catch (error) {console.log(error);
  }
})();

//Output - "promise 2 resolved at 400 ms"

从下面代码留神到 Promise.any() 次要关注解析的值。它会疏忽在 100 毫秒时回绝的 promise1,并思考在 400 毫秒后解析的promise2 的值。

实在用例

从最快的服务器检索资源

假如拜访咱们网站的用户可能来自寰球各地。如果咱们的服务器基于单个地位,那么响应工夫将依据每个用户的地位而不同。然而如果咱们有多个服务器,能够应用可能产生最快响应的服务器。在这种状况下,能够应用 Promise.any() 办法从最快的服务器接管响应。

我是小智,咱们下期再见!


代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

原文:https://blog.bitsrc.io/introd…

交换

文章每周继续更新,能够微信搜寻「大迁世界」第一工夫浏览和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,整顿了很多我的文档,欢送 Star 和欠缺,大家面试能够参照考点温习,另外关注公众号,后盾回复 福利,即可看到福利,你懂的。

退出移动版