Home > Web Front-end > JS Tutorial > Understand how to use Promise.race() and Promise.any()

Understand how to use Promise.race() and Promise.any()

青灯夜游
Release: 2020-12-21 09:32:08
forward
3843 people have browsed it

Understand how to use Promise.race() and Promise.any()

Related recommendations: "javascript video tutorial"

Since its release in 1996, JS has been steadily improving. With many improvements in ECMAScript versions, the most recent version is ES2020. An important update to JS is Promise, which was released under the name ES6 in 2015.

What is Promise?

MDN definition of Promise: Promise objects are used to represent the final completion (or failure) of an asynchronous operation and its result value. This may sound a bit too complicated for newbies.

A foreign elder explained Promises as follows: "Imagine you are a child. Your mother promises you that she will buy you a new mobile phone next week."

You won’t find out if you can get that phone until next week. Your mom will either actually buy you a brand new phone, or she won't buy it for you because she's unhappy.

This is a Promise. A Promise has three states. They are:

  1. Pending: You don’t know if you can get that phone
  2. Fulfilled: Mom is happy and bought it for you
  3. Rejected: Mom I'm sorry, I won't buy it for you

This is the fastest way to understand the Promise example I've heard so far.

If you haven’t started learning Promise yet, it is recommended that you do so.

Promise contains several very useful built-in methods. Today we mainly introduce these two methods.

  • Promise.race() - Released with ES6
  • Promise.any() - Proposal still in stage 4中

Promise.race()

Promise.race()The method was originally released when Promise was introduced in ES6. This method requires a iterable as parameters. The

Promise.race(iterable) method returns a promise that will be resolved or rejected once a promise in the iterator is resolved or rejected.

Unlike the Promise.any() method, the Promise.race() method mainly focuses on whether the Promise has been resolved, regardless of whether it is resolved or rejected.

Syntax

Promise.race(iterable)
Copy after login

Parameters

iterable — Iterable object, similar to Array. The iterable object implements the Symbol.iterator method.

Return Value

A pending Promise Whenever a promise in the given iteration resolves or rejects, take the value of the first promise as its value, Thereby asynchronously resolve or reject (once the stack is empty).

Note

Because the parameter accepts iterable, we can pass some values, such as basic values ​​or even objects in an array. In this case, the race method will return the first non-promise object passed. This is mainly because the behavior of the method is to return the value as soon as the value is available (when the promise is satisfied).

Additionally, if an already resolved Promise is passed in an iterable, the Promise.race() method will resolve to the first of that value. If an empty Iterable is passed, the race method will always be pending.

Example

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拒绝
Copy after login

Real Use Case

Now, you may be wondering, when do we use Promise.race() in practice? come and see.

Display loading animation when requesting data

It is very common to use loading animation in development. When the data response time is long, if the loading animation is not used, it will look like there is no response. But sometimes, the response is too fast. We need to add a very small delay time when loading the animation, which will make the user feel that I am requesting frequently. To achieve this, just use the Promise.race() method as shown below.

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();
});
Copy after login

Cancelled Promise

In some cases, we need to cancel the Promise. In this case, we can also use the Promise.race() method:

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);
Copy after login

Batch requests for long execution

Chris Jensen has an interesting use case for the race() method . He has used the Promise.race() method to batch long-running requests. This way they can keep the number of parallel requests fixed.

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 });
Copy after login

Promise.any()

Promise.any() Receives a Promise iterable object, as long as one of the promise If successful, return the successful promise. If none of the promise in the iterable object succeeds (that is, all promises fail/reject), a failed promise and an instance of type AggregateError are returned, It is a subclass of Error and is used to group single errors together. Essentially, this method is the opposite of Promise.all().

注意! Promise.any() 方法依然是实验性的,尚未被所有的浏览器完全支持。它当前处于 TC39 第四阶段草案(Stage 4)

语法

Promise.any(iterable);
Copy after login

参数

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"
Copy after login

从上面代码注意到Promise.any()主要关注解析的值。 它会忽略在100毫秒时拒绝的promise1,并考虑在400毫秒后解析的promise2的值。

真实用例

从最快的服务器检索资源

假设访问我们网站的用户可能来自全球各地。如果我们的服务器基于单个位置,那么响应时间将根据每个用户的位置而不同。但是如果我们有多个服务器,可以使用能够产生最快响应的服务器。在这种情况下,可以使用Promise.any()方法从最快的服务器接收响应。

原文地址:https://blog.bitsrc.io/introduction-to-promise-race-and-promise-any-with-real-life-examples-9d8d1b9f8ec9

作者:Mahdhi Rezvi

译文地址:https://segmentfault.com/a/1190000038475001

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of Understand how to use Promise.race() and Promise.any(). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template