小程序onLaunch异步问题解决方案

257 阅读1分钟

# 业务场景 

在使用uniapp开发小程序时,遇到了一个问题,在进入小程序时需要最先调用获取秘钥的接口才能进行后续的接口调用,否则后续的接口就是调用失败,所以,就把获取秘钥的接口放在了APP.vue的onLaunch中,但实际出现问题是,由于接口返回需要时间,所以无法保证秘钥返回之后再去调用首页的接口。 一开始想到的解决方法是把获取秘钥的函数也放到首页中调用,利用Promise确保调用的正确顺序,但后续还有其他页面也有成为首页直接进入的情况,比如扫码进入某个页面,所以这种方式感觉不是很优雅。上网搜索到的解决方案也都是利用Promise去实现。所以想到有没有其他方式可以实现。

 # 一些思路 

因为我项目中使用的是vue3,所以考虑可不可以参照hooks的方式去实现一下。 代码如下 

useAsyncLaunch.js

const useAsyncLaunch = (asyncCallBack) => {
  const asyncOnload = (onloadCallBack = (opts) => {}) => {
    return onLoad((options) => {
      uni.getStorage({
        key: 'storage_key',
        success: () => {
          asyncCallBack && asyncCallBack(options)
        },
        fail: () => {
          uni.$once('onlaunch', () => {
            asyncCallBack && asyncCallBack(options)
          })
        }
      });
      onloadCallBack(options)
    })
  }
  return { asyncOnload }
}

export default useAsyncLaunch

定义一个useAsyncLaunch方法,参数是一个回调函数,确保在秘钥返回后调用,并且传入可能需要的页面传参options,并返回一个回调函数,在这个回调函数中可以执行页面中的一些同步操作或者不需要秘钥的接口函数, 因为秘钥返回之后会添加到缓存中,所以加了一步判断,如果从缓存中取到秘钥,那么回调函数直接执行,如果获取失败,则借助uni.emit()uni.emit() uni.once() 方法,确保成功取到值,并且uni.$once()只执行一次自动移除,没有后续负担。

// 获取秘钥
export const getSegmentationKey = () => {
  try {
    console.log('api utils 从后端获取另一半密钥')
    uni.getStorage({
      key: 'storage_key',
      success: (res) => {
        keyObj.value = JSON.parse(res.data)
      },
      fail: () => {
        postGetKey(keyEncrypt()).then((res: any) => {
          keyObj.value = keyDecrypt(res.data.enc, getRandomNumToSign(res.data.sign))
          uni.$emit('onlaunch')
          uni.setStorage({
            key: 'storage_key',
            data: JSON.stringify(keyObj.value)
          });
        })
      }
    });
  } catch (e) {
    console.error('获取密钥失败', e)
  } 
}

在获取秘钥的方法中调用uni.$emit(),并将结果存入缓存中,以便于后续使用。

# 在页面中使用 

 引入useAsyncLaunch方法 

const { asyncOnload } = useAsyncLaunch((options) => {
  // options 页面传参
  getDictNoToken(['prdtAttr']).then((res: any) => {
    console.log(res)
  })
  // 其他需要异步调用的函数
})

asyncOnload((options) => {
     // options 页面传参
    // 其他操作
})

 此方式也适用于其他需要异步获取数据的请况如先获取token再执行其他操作的时候。