V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
firhome
V2EX  ›  程序员

wx 小程序的全局异步数据你们是如何加载管理的?

  •  3
     
  •   firhome · 2021-01-15 09:32:23 +08:00 · 4000 次点击
    这是一个创建于 1406 天前的主题,其中的信息可能已经有所发展或是发生改变。
    向各位开发过小程序的大佬们请教个问题。

    我有一个小程序,需要初始化一些远程数据 放全局 ( 小程序的各个页面可能都会使用到 )

    所以在 app onLaunch 的时候去请求~ 但是小程序页面并不会等 这个异步请求结束后再加载。所以会导致页面报错。

    那么官方给的解决方案是 app 里写 callback 。 我有很多页面都会用到这部分数据 可又不可能 每个页面去写 callback 。



    我自己想了两个解决方案。

    1. 小程序 onLaunch 的时候去本地存储找是否有这部分数据,如果有 不请求(直接使用,页面不会报错),如果没有那请求之后 再重新调用 pages 的 onload 加载一次(类似网页刷新) 页面。

    2.做一个空白( loading )页面当首页,等数据都加载好了 再跳 其它页面。

    想问问大家是怎么解决呢?
    35 条回复    2021-01-30 14:59:09 +08:00
    undertonememorie
        1
    undertonememorie  
       2021-01-15 09:35:58 +08:00
    在代码不做大改动情况下推荐第二种
    sjhhjx0122
        2
    sjhhjx0122  
       2021-01-15 09:37:20 +08:00
    如果没有那请求之后 再重新调用 pages 的 onload 加载一次(类似网页刷新) 页面。
    为什么不直接调用那个请求?
    firhome
        3
    firhome  
    OP
       2021-01-15 09:40:12 +08:00
    @sjhhjx0122 我描述错误,没加载的话 是要再请求一下接口 然后再重新 onload
    totoro52
        4
    totoro52  
       2021-01-15 09:42:06 +08:00
    onLaunch 不建议做网络请求
    firhome
        5
    firhome  
    OP
       2021-01-15 09:42:47 +08:00
    @totoro52 为什么呢,那这种该写到哪里呢
    hereIsChen
        6
    hereIsChen  
       2021-01-15 09:46:56 +08:00
    我们用的第二种方法,给了个加载页
    hereIsChen
        7
    hereIsChen  
       2021-01-15 09:47:16 +08:00
    类似 app 的启动页面
    hiro0729
        8
    hiro0729  
       2021-01-15 09:48:03 +08:00
    写个通用的方法,里面先判断是否 globalData 里有没有数据,有直接 resolve,没有异步取得后 resolve,各个页面的 onShow:async ()=>{}或 onLoad:async ()=>{}里,都先 await 调用一下这个方法
    varzy
        9
    varzy  
       2021-01-15 09:56:01 +08:00
    我使用的方法类似于 8 楼,只不过是用了回调的语法。简单给个 demo 吧,写得不好勿喷。

    <script async src="//jsfiddle.net/varzy/nk2071se/1/embed/js/"></script>
    sujin190
        10
    sujin190  
       2021-01-15 09:58:28 +08:00
    或者在全局重新定义一下 Page,这样就是可以直接替换掉每个页面的 onLoad 方法,加入等待 onLaunch 加载完的流程就好了
    varzy
        11
    varzy  
       2021-01-15 09:58:30 +08:00
    @varzy #9 不知道怎么插入 jsfiddle 的预览。。。放个链接吧: https://jsfiddle.net/varzy/nk2071se/1/
    sjhhjx0122
        12
    sjhhjx0122  
       2021-01-15 10:02:59 +08:00
    @firhome 那就最简单方式,封装一下请求,在发送请求之前判断一下 globalData 里有没有数据,没有数据就先发全局数据的那个请求,拿到数据在请求当前请求
    firhome
        13
    firhome  
    OP
       2021-01-15 10:04:41 +08:00
    @sujin190 我正在尝试这个方法,但发现 onLoad 会不停的重新加载,有 demo 可以学习下吗?
    tjxone
        14
    tjxone  
       2021-01-15 10:08:49 +08:00
    将获取去全局数据的方法挂载再 app.js 上,该方法用 promise 封装好,作好缓存判断
    后面每个页面的请求都先调用这个方法再请求各自页面的数据就可以了

    app.js
    getGlobalData(){return new Promise((resolve,reject)=>{ 先判断有无全局数据,无就请求数据再 resolve })}

    其他各个页面
    getApp().getGlobalData.then(自己的业务)
    sam014
        15
    sam014  
       2021-01-15 10:10:29 +08:00
    第二项感觉不错,顺便还能加个开屏广告,2333333333333

    小程序用的 taro+mobx,全局数据放 mobx + run 调用 ,感觉比原生语法方便多了
    totoro52
        16
    totoro52  
       2021-01-15 10:24:11 +08:00
    @firhome 因为你在这里做网络请求,如果你从服务器拉取一些特定的全局属性,还没拉取完就加载下个方法了 因为它是异步的,如果下面的方法用到这些属性就炸了 ,如果你非要在这做请求,你的第二个方案是可以的
    tjxone
        17
    tjxone  
       2021-01-15 10:26:56 +08:00
    @sam014 第二项的话,如果分享页面就无法跳过去了
    sam014
        18
    sam014  
       2021-01-15 10:36:29 +08:00
    @tjxone 没有完美的方案,有舍有得,所以我选 taro+mobx
    cczeng
        19
    cczeng  
       2021-01-15 10:41:04 +08:00
    弱弱的问一下,发布订阅模式不适用吗
    phpcxy
        20
    phpcxy  
       2021-01-15 13:11:49 +08:00
    第二个方案没考虑非首页进入的情况啊?
    preach
        21
    preach  
       2021-01-15 13:46:03 +08:00
    zhyl
        22
    zhyl  
       2021-01-15 13:54:10 +08:00
    第二种方案,然后在 app.onShow 中进行数据加载和页面跳转
    MENGKE
        23
    MENGKE  
       2021-01-15 14:40:06 +08:00
    可以用 defineProperty 吧,或者 ES6 的 proxy ;
    https://blog.csdn.net/qq_17497931/article/details/108109947
    nekochyan
        24
    nekochyan  
       2021-01-15 15:49:40 +08:00
    我们的解决方案 第一步就像你说的那样 onLaunch 的时候去本地存储找是否有这部分数据,如果有不请求,直接使用
    第二个是写一个通用的事件通知,没数据的话注册监听在 onLaunch 里面,然后数据返回的时候 trigger 一下事件所有监听的地方就刷新了
    nekochyan
        25
    nekochyan  
       2021-01-15 16:00:12 +08:00
    就是楼上说的发布订阅模式
    lutian
        26
    lutian  
       2021-01-15 16:06:52 +08:00
    aa
    GzhiYi
        27
    GzhiYi  
       2021-01-15 16:30:49 +08:00
    响应式原理可解。
    懒得写的话用 omix 。
    https://github.com/Tencent/omi/tree/master/packages/omix
    miloooz
        28
    miloooz  
       2021-01-15 16:39:10 +08:00
    我做了些封装
    1. app.ts 检查 token 是否存在,存在则直接请求 token,不存在则先请求 token,再请求全局公共数据(这里的判断是放在 store 里的)
    2. 封装 http 请求,没有 token 则拦截所有的请求,先把 token 请求到再把拦截的请求全部放行(这里的判断是放在 http 的封装里的)

    有一种情况就是,页面内的请求依赖全局的内容时,这里涉及到顺序。页面我用了 computed 插件,watch 监听 store 里被依赖的数据。如果被依赖的数据为空,则不执行,等到 app.ts 里请求到了全局公共数据,触发 wetch,再请求。
    SakuraKuma
        29
    SakuraKuma  
       2021-01-15 16:39:17 +08:00
    patch 一下 Page, hook 一下 onload 加绑个事件, app 获取完数据 trigger/emit.
    miloooz
        30
    miloooz  
       2021-01-15 16:41:28 +08:00
    全局的 store 和 computed 插件 这个官方的扩展里都有,引到项目里用就可以了
    https://developers.weixin.qq.com/miniprogram/dev/extended/utils/computed.html
    miloooz
        31
    miloooz  
       2021-01-15 16:45:47 +08:00
    啊 上面的写错了
    1. app.ts 检查 token 是否存在,存在则直接请求全局公共数据,不存在则先请求 token,再请求全局公共数据(这里的判断是放在 store 里的)
    yehuzi
        32
    yehuzi  
       2021-01-15 16:53:28 +08:00
    发布 /订阅模式应该可以解决楼主的问题吧: https://aotu.io/notes/2017/01/19/wxapp-event/
    looppppp
        33
    looppppp  
       2021-01-15 20:31:03 +08:00
    接管 Page 全局方法,代理一下 onLoad 这些生命周期方法,然后就可以接入 redux 了,爽歪歪
    ersic
        34
    ersic  
       2021-01-15 20:38:43 +08:00 via Android
    了解一下预加载跟周期性拉取得特性
    cxe2v
        35
    cxe2v  
       2021-01-30 14:59:09 +08:00
    我写的方案是,第一次 lanuch 的时候获取全局数据,存到 app.js 的一个自定义的全局变量里,以后页面上要用自己去 app.globalData 里去拿,当然小程序是有一个加载界面的,在 lanuch 的时候一直处于加载动画上,所以用户体验稍微好一点
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1232 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 18:01 · PVG 02:01 · LAX 10:01 · JFK 13:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.