承诺链中的重试功能

Retry functionality in promise chain

我有一个承诺链

如果我在 getServiceCost 中收到错误,我想再次重复链(重试)2 次,当我使用 Promise 链时如何实现这一点,这意味着再次执行 getUser、getServiceCost

getUser(100)
    .then(getServices)
    .then(getServiceCost)
    .then(console.log);


function getUser(userId) {
    return new Promise((resolve, reject) => {
        console.log('Get the user from the database.');
        setTimeout(() => {
            resolve({
                userId: userId,
                username: 'admin'
            });
        }, 1000);
    })
}

function getServices(user) {
    return new Promise((resolve, reject) => {
        console.log(`Get the services of ${user.username} from the API.`);
        setTimeout(() => {
            resolve(['Email', 'VPN', 'CDN']);
        }, 3 * 1000);
    });
}

function getServiceCost(services) {
    return new Promise((resolve, reject) => {
        console.log(`Calculate the service cost of ${services}.`);
        setTimeout(() => {
            resolve(services.length * 100);
        }, 2 * 1000);
    });
}

如果我在 getServiceCost 中收到错误我想再次重复链(重试)2 次我如何在使用 Promise 链时实现这一点,这意味着再次执行 getUser, getServiceCost

我会使用一个 async 函数(所有现代环境都支持它们,并且您可以为过时的环境进行转换),它允许您使用一个简单的循环。也许作为一个效用函数你可以重用:

async function callWithRetry(fn, retries = 3) {
    while (retries-- > 0) {
        try {
            return await fn();
        } catch (error) {
            if (retries === 0) {
                throw error;
            }
        }
    }
    return new Error(`Out of retries`); // Probably using an `Error` subclass
}

使用它:

callWithRetry(() => getUser(100).then(getServices).then(getServiceCost))
.then(console.log)
.catch(error => { /*...handle/report error...*/ });

或者

callWithRetry(async () => {
    const user = await getUser(100);
    const services = await getServices(user);
    return await getServiceCost(services);
})
.then(console.log)
.catch(error => { /*...handle/report error...*/ });