single promise

实现一个单例的promise。

问题

javascript中对网络的请求都是异步调用。
比如小程序在访问页面时,如果需要用到用户的openid,那么避免不了需要先做登录处理。
但是当所有的请求都同时发出时,所有的请求都会执行一遍登录,这显然效率不高。
那么如果有一个请求已经发起了登录请求,那么后续的请求只要排队等着即可。

方案

解决方案有两种。

  • 做一个队列,用一个flag来标识是否在登录请求中,如果是的话,就把后续的请求放到队列里。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    let localToken = wx.getStorageSync(LOCAL_TOKEN_KEY);
    const loginQueue = [];
    let isLoginning = false;
    function getToken() {
    return new Promise((resolve, reject) => {
    if (!localToken) {
    loginQueue.push({
    resolve,
    reject
    })
    if (!isLoginning) {
    isLoginning = true
    internalLogin().then(token => {
    while (loginQueue.length) {
    loginQueue.shift().resolve(token);
    }
    }).catch(loginError).finally(() => {
    isLoginning = false;
    })
    }
    } else {
    resolve(localToken)
    }
    })
    }
  • 实现一个单例的promise,所有请求都用这个promise来获取token

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    let localToken = wx.getStorageSync(LOCAL_TOKEN_KEY);
    const promiseSingleton = (fn) => {
    let _ret = null
    return (...args) => {
    if (_ret) {
    return _ret
    }
    _ret = fn(...args)
    _ret.then(res => {
    _ret = null
    return res
    }).catch(err => {
    _ret = null
    return Promise.reject(err)
    })
    return _ret
    }
    }
    const singleLogin = promiseSingleton(internalLogin)
    function getToken() {
    console.log("gettoken")
    return new Promise((resolve, reject) => {
    if (!localToken) {
    singleLogin().then(token => {
    resolve(token)
    }).catch(loginError)
    } else {
    resolve(localToken)
    }
    })
    }