Promise对象finally执行时机

345 阅读1分钟

首先来看下finally在Promise的作用,

finally 会在 then 和 catch 之后执行,无论 then 和 catch 中是否抛出异常

相信这个都比较清楚,下面我来说说我在开发中遇到的bug。

代码大概如下

<!-- 保存按钮防抖 -->
const [loading,setLoading] = useState(false)

<!-- 保存操作 -->
const save = (cb) => {
    setLoading(true)
    request('/save', {
        ...params
    }).then(() => {
        if (cb) {
            cb()
        } else {
            message.success('保存成功')
        }
    }).finally(() => {
        setLoading(false)
    })
}

<!-- 第一种情况 无callback直接执行保存操作 -->
save()

<!-- 第二种情况 有callback,且此callback中有另一个异步请求操作 -->
save(() => {
    request('/saveConfirm').then(() => {
        message.success('保存成功')
    })
})

这代代码的大概场景就是在若有cb的情况下,需要等待cb的异步请求执行完后,再把保存操作的按钮loading设置为false,防止用户再次点击。

而问题就出现在防抖失效了,经过调试发现,finally中的setLoading(false)已经提前执行,并没有等待then中的异步请求完成才执行,导致防抖失效。

总结

finally 在 then 或 catch 的同步操作完成后会立即执行, 然而finally 并不会等待 then 或 catch 内部的异步操作完成,除非这些异步操作的结果被返回并传递给下一个 Promise 链。

const save = (cb) => {
    setLoading(true)
    request('/save', {
        ...params
    }).then(() => {
        if (cb) {
            // 返回新的Promise对象
            return new Promise((resolve) => {
                 cb(resolve)
            })
        } else {
            message.success('保存成功')
        }
    }).finally(() => {
        setLoading(false)
    })
}

save((resolve) => {
    request('/saveConfirm').then(() => {
        message.success('保存成功')
        resolve(null)
    })
})