myfreax

JavaScript Promise.race 静态方法

您将学习如何使用 JavaScript Promise.race() 静态方法

JavaScript Promise.race 静态方法
JavaScript Promise.race 静态方法

在本教程中,您将学习如何使用 JavaScript Promise.race() 静态方法。

JavaScript Promise.race() 静态方法介绍

Promise.race() 静态方法接受一个 Promise 一个可迭代的列表对象,并返回一个新的 Promise,一旦有一个 Promise 解决或拒绝,就会返回一个解决或拒绝的 Promise,以及 Promise 的值或拒绝原因。

下面是 Promise.race() 方法的语法:

Promise.race(iterable)

在此语法中,iterable 是一个包含 Promise 列表的可迭代对象

Promise.race() 的名称意味着所有的 Promise 都相互竞争,无论是解决还是拒绝。

见下图:

在此图中:

  • promise1t1 时返回 v1 值并解决。
  • promise2error 在 t2 被拒绝。
  • 因为 promise1promise2 更早解决,所以 promise1 赢得竞争。因此,Promise.race([promise1, promise2]) 返回一个新的 Promise, 在 t1 时被解决与 v1 值。

再看一张图:

在此图中:

  • promise1t2 时被解决与 v1 值。
  • promise2errort1 时被拒绝。
  • 因为 promise2promise1 更早解决,所以 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 的值或错误。

内容导航