JavaScript 停止并行函数调用

JavaScript Stall Parallel Function Calls

我创建了一个 TokenService class,目的是 return 访问令牌。 getToken 函数检查令牌是否已过期,如果为真,它将尝试在给定 refreshToken 的情况下获取新的 accessToken。但是,重要的是只有一个请求会尝试刷新令牌。因此,如果函数被并行调用,它需要等到第一个调用完成并且 return 所有其他调用的结果。

这是我当前的实现:

class TokenService {
    private isRefreshing: boolean = false

    public getToken = async (): Promise<string> => {
        const accessToken = window.localStorage.getItem('accessToken')
        if (!accessToken) return Promise.resolve(null)

        // Check if token has expired
        const { exp } = JSON.parse(atob(accessToken.split('.')[1]))
        if (new Date() < new Date(exp * 1e3))
            return Promise.resolve(accessToken)
            

        if (this.isRefreshing) {
            // Wait for request to finish and return result
        }

        // Refresh token
        this.isRefreshing = true
        const refreshedAccessToken = await this.refreshToken()
        return Promise.resolve(refreshedAccessToken)
    }
}

我添加了一个标志 isRefreshing 指示当前是否有正在进行的刷新请求。我不确定如何从这里开始。我如何等待请求完成并 return 结果?

您必须先通过 this 来引用 isRefreshing - 它不是独立的标识符。

刷新令牌时,将Promise的结果分配给class上的属性。这将使 getToken 到 return 的进一步调用,如果 Promise 存在。如果它不存在,并且当前令牌已过期,则生成另一个。

因为你有时Promise.resolve(null),你有时return null,不是字符串,所以你应该适当地更改getToken的类型签名。

class TokenService {
    private tokenPromise: null | Promise<string> = null;

    public getToken = async (): Promise<string | null> => {
        const accessToken = window.localStorage.getItem('accessToken')
        if (!accessToken) return null;
        // Check if token has expired
        const { exp } = JSON.parse(atob(accessToken.split('.')[1]))
        if (new Date() <= new Date(exp * 1e3)) {
            // no need to retrieve another
            return accessToken;
        }
        if (this.tokenPromise) return this.tokenPromise;
        this.tokenPromise = this.refreshToken()
            .catch((error) => {
                window.localStorage.removeItem('accessToken');
                return null;
            })
            .finally(() => {
                this.tokenPromise = null;
            });
        return this.tokenPromise;
    }
}