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.
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:
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()
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.
Promise.race(iterable)
iterable
— Iterable object, similar to Array. The iterable object implements the Symbol.iterator
method.
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).
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.
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拒绝
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(); });
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);
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 });
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);
iterable
— 个可迭代的对象, 例如 Array。
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()
方法从最快的服务器接收响应。
原文地址: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!