在本教程中,您将学习如何使用 JavaScript Promise.race()
静态方法。
JavaScript Promise.race() 静态方法介绍
Promise.race()
静态方法接受一个 Promise 一个可迭代的列表对象,并返回一个新的 Promise,一旦有一个 Promise 解决或拒绝,就会返回一个解决或拒绝的 Promise,以及 Promise 的值或拒绝原因。
下面是 Promise.race()
方法的语法:
Promise.race(iterable)
在此语法中,iterable
是一个包含 Promise 列表的可迭代对象。
Promise.race()
的名称意味着所有的 Promise 都相互竞争,无论是解决还是拒绝。
见下图:
在此图中:
promise1
在t1
时返回v1
值并解决。promise2
因error
在 t2 被拒绝。- 因为
promise1
比promise2
更早解决,所以promise1
赢得竞争。因此,Promise.race([promise1, promise2])
返回一个新的 Promise, 在t1
时被解决与 v1 值。
再看一张图:
在此图中:
promise1
在t2
时被解决与v1
值。promise2
因error
在t1
时被拒绝。- 因为
promise2
比promise1
更早解决,所以promise2
赢得竞争。因此,Promise.race([promise1, promise2])
返回一个在t1
时因error
被拒绝Promise 。
JavaScript Promise.race() 示例
让我们举一些使用 Promise.race()
静态方法的例子。
简单的 JavaScript Promise.race()
下面创建两个 Promise:一个在 1 秒内解决,另一个在 2 秒内解决。因为第一个 Promise 比第二个解决得更快,所以 Promise.race()
使用第一个 Promise 的值解决:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The first promise has resolved');
resolve(10);
}, 1 * 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The second promise has resolved');
resolve(20);
}, 2 * 1000);
});
Promise.race([p1, p2])
.then(value => console.log(`Resolved: ${value}`))
.catch(reason => console.log(`Rejected: ${reason}`));
输出:
The first promise has resolved
Resolved: 10
The second promise has resolved
下面示例创建两个承诺。第一个 promise 在 1 秒内解决,而第二个 promise 在 2 秒内拒绝。因为第一个 promise 比第二个快,所以返回的 promise 解析为第一个 promise 的值:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The first promise has resolved');
resolve(10);
}, 1 * 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The second promise has rejected');
reject(20);
}, 2 * 1000);
});
Promise.race([p1, p2])
.then(value => console.log(`Resolved: ${value}`))
.catch(reason => console.log(`Rejected: ${reason}`));
输出
The first promise has resolved
Resolved: 10
The second promise has rejected
请注意,如果第二个 promise 比第一个快,则返回的 promise 会因为第二个 promise 的原因而被拒绝。
JavaScript Promise.race() 实践
假设如果从服务器加载数据的时间超过几秒,您必须显示一个加载指示器。
因此,您可以使用 Promise.race()
静态方法。如果发生超时,则显示加载指示器,否则显示消息。
下面一段简单的 HTML 代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Promise.race() Demo</title>
<style>
body {
font-family: 'Open Sans', sans-serif;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
}
#container {
background-color: #fff;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
max-width: 400px;
margin: 10px auto;
padding: 16px;
width: 300px;
text-align: center;
}
#message {
margin-bottom: 10px;
padding: 10px 5px 10px;
text-align: left;
}
button {
box-sizing: border-box;
width: 100%;
padding: 3%;
background: #007bff;
border-bottom: 2px solid #007bff;
border-top-style: none;
border-right-style: none;
border-left-style: none;
color: #fff;
}
button:hover {
background: #0069d9;
cursor: pointer;
}
.loader {
border: 8px solid #f3f3f3;
border-radius: 50%;
border-top: 8px solid #F9DC5C;
width: 25px;
height: 25px;
margin: 0 auto;
text-align: center;
-webkit-animation: spin 2s linear infinite;
/* Safari */
animation: spin 2s linear infinite;
}
/* Safari */
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div id="container">
<button id="btnGet">Get Message</button>
<div id="message"></div>
<div id="loader"></div>
</div>
<script src="js/promise-race.js"></script>
</body>
</html>
要创建加载指示器,我们使用 CSS 动画。从技术上讲,如果一个元素有类 .loader
,它会显示加载指示器。
首先,定义一个加载数据的函数。它使用 setTimeout()
来模拟异步操作:
const DATA_LOAD_TIME = 5000;
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const message = 'Promise.race() Demo';
resolve(message);
}, DATA_LOAD_TIME);
});
}
其次,定义一个显示消息内容的函数:
function showContent(message) {
document.querySelector('#message').textContent = message;
}
此函数也可用于将 message
设置为空白。
第三,定义 timeout()
函数并返回 Promise。当经过指定的时间时,Promise将拒绝。
const TIMEOUT = 500;
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => reject(), TIMEOUT);
});
}
第四,定义显示和隐藏加载指示器的函数:
function showLoadingIndicator() {
document.querySelector('#loader').className = 'loader';
}
function hideLoadingIndicator() {
document.querySelector('#loader').className = '';
}
第五,将点击事件添加到“Get Message”按钮。在点击事件回调中,使用Promise.race()
静态方法:
// 按钮点击事件
const btn = document.querySelector('#btnGet');
btn.addEventListener('click', () => {
// 如果用户点击多次则重置 UI
reset();
// 显示消息内容或者显示加载器
Promise.race([getData()
.then(showContent)
.then(hideLoadingIndicator), timeout()
])
.catch(showLoadingIndicator);
});
我们将两个 Promise 传递给 Promise.race()
方法:
Promise.race([getData()
.then(showContent)
.then(hideLoadingIndicator), timeout()
])
.catch(showLoadingIndicator);
第一个 Promise 从服务器获取数据,显示内容,并隐藏加载指示器。第二个 Promise 设置超时。
如果第一个 promise 需要超过 500 毫秒才能解决,则调用 catch()
显示加载指示器。一旦第一个 promise 解决,它就会隐藏加载指示器。
最后,定义 reset()
函数,如果第二次单击按钮,则隐藏消息和加载指示器。
// 重置 UI
function reset() {
hideLoadingIndicator();
showContent('');
}
把它们放在一起。
// 如果显示加载指示器 0.5秒后 getData() 没有解决
const TIMEOUT = 500;
const DATA_LOAD_TIME = 5000;
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const message = 'Promise.race() Demo';
resolve(message);
}, DATA_LOAD_TIME);
});
}
function showContent(message) {
document.querySelector('#message').textContent = message;
}
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => reject(), TIMEOUT);
});
}
function showLoadingIndicator() {
document.querySelector('#loader').className = 'loader';
}
function hideLoadingIndicator() {
document.querySelector('#loader').className = '';
}
//按钮点击事件
const btn = document.querySelector('#btnGet');
btn.addEventListener('click', () => {
// 如果用户点击第二次则重置 UI
reset();
// 显示消息内容或者加载指示器
Promise.race([getData()
.then(showContent)
.then(hideLoadingIndicator), timeout()
])
.catch(showLoadingIndicator);
});
// 重置UI
function reset() {
hideLoadingIndicator();
showContent('');
}
结论
Promise.race(iterable)
方法返回一个新的Promise
,一旦 iterable 中的 Promise 之一解决或拒绝,该 Promise 就会解决或拒绝,并返回该 Promise 的值或错误。