javascript 了解 promise.race() 的用法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46376432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding promise.race() usage
提问by Martin AJ
As far as I know, there are two options about promise:
据我所知,有两种选择promise:
Ok, I know what promise.all()does. It runs promises in parallel, and .thengives you the values if both resolved successfully. Here is an example:
好的,我知道是promise.all()做什么的。它并行运行承诺,.then如果两者都成功解决,则为您提供值。下面是一个例子:
Promise.all([
$.ajax({ url: 'test1.php' }),
$.ajax({ url: 'test2.php' })
])
.then(([res1, res2]) => {
// Both requests resolved
})
.catch(error => {
// Something went wrong
});
But I don't understand what does promise.race()is supposed to do exactly? In other word, what's the difference with not using it? Assume this:
但我不明白究竟promise.race()应该做什么?换句话说,不使用它有什么区别?假设:
$.ajax({
url: 'test1.php',
async: true,
success: function (data) {
// This request resolved
}
});
$.ajax({
url: 'test2.php',
async: true,
success: function (data) {
// This request resolved
}
});
See? I haven't used promise.race()and it behaves like promise.race(). Anyway, is there any simple and clean example to show me when exactly should I use promise.race()?
看?我没有使用过promise.race(),它的行为就像promise.race(). 无论如何,是否有任何简单而干净的示例可以告诉我什么时候应该使用promise.race()?
回答by JiangangXiong
As you see, the race()will return the promise instance which is firstly resolved or rejected:
如您所见,race()将返回首先解决或拒绝的承诺实例:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// Both resolve, but p2 is faster
});
For a scenes to be used, maybe you want to limit the cost time of a request :
对于一个要使用的场景,也许你想限制一个请求的成本时间:
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
With the race()you just need to get the returned promise, you needn't care about which one of the promises in the race([])firstly returned,
有了race()你只需要得到返回的promise,你就不用关心第一个返回的promise中的哪一个race([]),
However, without the race, just like your example, you need to care about which one will firstly returned, and called the callback in the both successcallback.
但是,没有race,就像您的示例一样,您需要关心哪个将首先返回,并在两个success回调中调用回调。
回答by ChrisJ
I've used it for request batching. We had to batch tens of thousands of records into batches for a long running execution. We could do it in parallel, but didn't want the number of pending requests to get out of hand.
我已经将它用于请求批处理。为了长时间运行,我们不得不将数以万计的记录分批处理。我们可以并行执行,但不希望待处理请求的数量失控。
Race lets us keep a fixed number of parallel promises running and add one to replace whenever one completes
Race 让我们保持固定数量的并行 promise 运行,并在完成时添加一个以替换
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 });
回答by Iiridayn
It's a piece to build a timeout system, where:
这是构建超时系统的一部分,其中:
- the request/computation may be canceled by another channel
- it will still be used later, but we need an interaction now.
- 请求/计算可能被另一个通道取消
- 以后还会用到,但是现在需要交互了。
For an example of the second, one might show a spinner "instantly" while still defaulting to show real content if it comes in fast enough. Try running the below a few times - note at least some console message comes "instantly". This might normally be attached to perform operations on a UI.
对于第二个例子,一个人可能会“立即”显示一个微调器,同时如果它足够快的话仍然默认显示真实的内容。尝试运行以下几次 - 请注意,至少有一些控制台消息“立即”出现。这通常可能会附加到在 UI 上执行操作。
The key to note is - the result of Promise.raceis much less important than the side effects (though, this then is a code smell).
需要注意的关键是 - 结果Promise.race远不如副作用重要(不过,这就是代码异味)。
// 300 ms _feels_ "instant", and flickers are bad
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();
});
Inspiration credit to a comment by captainkovalsky.
灵感归功于船长科瓦尔斯基的评论。
An example of the first:
第一个例子:
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);
You can see from this one that the timeout's console.logis never executed when the timeout hits first. It should fail/succeed about half/half, for testing convenience.
从这个可以看出,console.log当超时第一次命中时,永远不会执行超时。为了测试方便,它应该失败/成功大约一半/一半。
回答by thelmuxkriovar
Here's an easy example to understand the use of promise.race():
这是一个简单的例子来理解使用promise.race():
Imagine you need to fetch some data from a server and if the data takes too long to load (say 15 seconds) you want to show an error.
想象一下,您需要从服务器获取一些数据,如果数据加载时间过长(比如 15 秒),您想要显示错误。
You would call promise.race() with two promises, the first being your ajax request and the second being a simple setTimeout(() => resolve("ERROR"), 15000)
您将使用两个承诺调用 promise.race(),第一个是您的 ajax 请求,第二个是一个简单的 setTimeout(() => resolve("ERROR"), 15000)
回答by Willem van der Veen
Summary:
概括:
Promise.raceis a JS built in function that accepts an iterable of Promises (e.g. Array) as an argument. This function then asynchronouslyreturns a Promise as soon as one in of the Promises passed in the iterable is either resolved or rejected.
Promise.race是一个 JS 内置函数,它接受可迭代的 Promise(例如Array)作为参数。然后,一旦在可迭代对象中传递的 Promise 中的一个被解决或被拒绝,此函数就会异步返回一个 Promise。
Example 1:
示例 1:
var promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-one'), 500);
});
var promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-two'), 100);
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster than promise 1
});
In this example first an array of Promises is passed in Promise.race. Both of the promises resolve but promise1 resolves faster. Therefore the promise is resolved with the value of promise1, which is the string 'Promise-one'.
在这个例子中,首先传入了一个 Promises 数组Promise.race。两个承诺都解决了,但 promise1 解决得更快。因此,promise 被解析为 promise1 的值,也就是字符串'Promise-one'。
Example 2:
示例 2:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('succes'), 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject('err'), 1000);
});
Promise.race([promise1, promise2])
.then((value) => {
console.log(value);
}).catch((value) => {
console.log('error: ' + value);
});
In this second example the second promise rejects faster than the first promise can resolve. Therefore Promise.racewill return a rejected promise with the value of 'err'which was the value that Promise2 rejected with.
在第二个示例中,第二个 Promise 的拒绝速度比第一个 Promise 解决的速度快。因此Promise.race将返回一个被拒绝的承诺,其值'err'是 Promise2 拒绝的值。
The key point to understand is that Promice.racetakes an iterable of Promises and returns a Promise based on the first resolved or rejected promise in that iterable (with the corresponding resolve()or reject()values).
要理解的关键点是,它Promice.race接受一个可迭代的 Promise 并根据该可迭代中的第一个已解决或被拒绝的承诺(具有相应的resolve()或reject()值)返回一个 Promise 。
回答by rab
Let's take an sample workaround of Promise.racelike below.
让我们采用Promise.race下面的示例解决方法。
const race = (promises) => {
return new Promise((resolve, reject) => {
return promises.forEach(f => f.then(resolve).catch(reject));
})
};
You can see racefunction executes all promises, but whomever finishes first will resolve/reject with wrapper Promise.
您可以看到racefunction 执行所有 promise,但先完成的人将使用 wrapper 解决/拒绝Promise。

