JavaScript Promise.race()

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

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

Promise.race() 静态方法接受一个包含 promise 的可迭代对象,并返回一个新的 promise。该 promise 一旦其中一个 promise fulfilled 或 reject,就会立即 fulfilled 或 reject,并带有该 promise 的值或原因。

以下是 Promise.race() 方法的语法

Promise.race(iterable)Code language: JavaScript (javascript)

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

Promise.race() 的名称暗示所有 promise 彼此竞争,只有一个赢家,无论成功还是失败。

请参见以下图表

在这个图表中

  • promise1t1 时用值 v1 fulfilled。
  • promise2t2 时用 error reject。
  • 由于 promise1promise2 提前完成,promise1 获胜。因此,Promise.race([promise1, promise2]) 返回一个新的 promise,该 promise 在 t1 时用值 v1 fulfilled。

请参见另一个图表

在这个图表中

  • promise1t2 时用 v1 fulfilled。
  • promise2t1 时用 error reject。
  • 由于 promise2promise1 提前完成,promise2 获胜。因此,Promise.race([promise1, promise2]) 返回一个新的 promise,该 promise 在 t1 时用 error reject。

JavaScript Promise.race() 示例

让我们来看一些使用 Promise.race() 静态方法的示例。

1) 简易 JavaScript Promise.race() 示例

以下代码创建了两个 promise:一个在 1 秒后完成,另一个在 2 秒后完成。由于第一个 promise 比第二个 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}`));
Code language: JavaScript (javascript)

输出

The first promise has resolved
Resolved: 10
The second promise has resolved

以下示例创建了两个 promise。第一个 promise 在 1 秒后完成,而第二个 promise 在 2 秒后失败。由于第一个 promise 比第二个 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}`));
Code language: JavaScript (javascript)

输出

The first promise has resolved
Resolved: 10
The second promise has rejected

请注意,如果第二个 promise 比第一个 promise 快,返回的 promise 就会因为第二个 promise 的原因而失败。

2) 实际 JavaScript Promise.race() 示例

假设您需要在从服务器加载数据时显示一个加载指示器,如果加载时间超过一定秒数。

为此,您可以使用 Promise.race() 静态方法。如果发生超时,您显示加载指示器,否则,您显示消息。

以下示例说明了 HTML 代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>JavaScript Promise.race() Demo</title>
    <link href="css/promise-race.css" rel="stylesheet">
</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>
Code language: HTML, XML (xml)

为了创建加载指示器,我们使用 CSS 动画功能。有关更多信息,请参见 promise-race.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);
    });
}
Code language: JavaScript (javascript)

其次,开发一个用于显示某些内容的函数

function showContent(message) {
    document.querySelector('#message').textContent = message;
}Code language: JavaScript (javascript)

该函数还可用于将 message 设置为空。

第三,定义 timeout() 函数,该函数返回一个 promise。当指定的 TIMEOUT 超时时,该 promise 将被拒绝。

const TIMEOUT = 500;

function timeout() {
    return new Promise((resolve, reject) => {
        setTimeout(() => reject(), TIMEOUT);
    });
}Code language: JavaScript (javascript)

第四,开发两个函数,用于显示和隐藏加载指示器

function showLoadingIndicator() {
    document.querySelector('#loader').className = 'loader';
}

function hideLoadingIndicator() {
    document.querySelector('#loader').className = '';
}Code language: JavaScript (javascript)

第五,向获取消息按钮附加一个点击事件监听器。在点击处理程序内,使用 Promise.race() 静态方法

// handle button click event
const btn = document.querySelector('#btnGet');

btn.addEventListener('click', () => {
    // reset UI if users click the 2nd, 3rd, ... time
    reset();
    
    // show content or loading indicator
    Promise.race([getData()
            .then(showContent)
            .then(hideLoadingIndicator), timeout()
        ])
        .catch(showLoadingIndicator);
});Code language: JavaScript (javascript)

我们将两个 promise 传递给 Promise.race() 方法

Promise.race([getData()
            .then(showContent)
            .then(hideLoadingIndicator), timeout()
        ])
        .catch(showLoadingIndicator);Code language: JavaScript (javascript)

第一个 promise 从服务器获取数据,显示内容,并隐藏加载指示器。第二个 promise 设置一个超时。

如果第一个 promise 需要超过 500 毫秒才能完成,则调用 catch() 来显示加载指示器。第一个 promise 完成后,它会隐藏加载指示器。

最后,开发一个 reset() 函数,如果按钮被第二次点击,则隐藏消息和加载指示器。

// reset UI
function reset() {
    hideLoadingIndicator();
    showContent('');
}Code language: JavaScript (javascript)

将所有内容组合在一起。

// after 0.5 seconds, if the getData() has not resolved, then show 
// the Loading indicator
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 = '';
}


// handle button click event
const btn = document.querySelector('#btnGet');

btn.addEventListener('click', () => {
    // reset UI if users click the second time
    reset();

    // show content or loading indicator
    Promise.race([getData()
            .then(showContent)
            .then(hideLoadingIndicator), timeout()
        ])
        .catch(showLoadingIndicator);
});

// reset UI
function reset() {
    hideLoadingIndicator();
    showContent('');
}Code language: JavaScript (javascript)

总结

  • Promise.race(iterable) 方法返回一个新的 promise,该 promise 一旦可迭代对象中的一个 promise fulfilled 或 reject,就会立即 fulfilled 或 reject,并带有该 promise 的值或错误。

测验

本教程对您有帮助吗?