一次同步与多次异步结合

本发明提出了一种在移动小程序中优化数据请求的方法,通过一次同步调用原生接口获取环境变量,然后将其全局存储,避免频繁调用导致的性能问题。在确保H5http数据请求正确性的基础上,采用异步请求提高执行速度,提升了用户体验。主要技术点包括使用Promise封装异步接口,同步获取环境变量并存储,以及异步执行H5http数据请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 相关技术背景(背景技术),与本发明最相近似的现有实现方案(现有技术)

1.1 背景技术

移动小程序框架mPaas, 为H5应用提供原生能力的自定义接口JSAPI,利用这些接口使用更多的原生功能,提高H5应用的用户体验。例如获取环境变量接口,初始化小程序应用时,有多条H5 http数据请求需要执行,为了保证H5数据请求的正确执行,需要初始化应用之前调用原生获取环境变量接口,根据监听原生异步回调函数获取环境变量,执行下一步的H5 http数据请求。

1.2 与本发明相关的现有技术一

1.2.1 现有技术一的技术方案

由于H5从原生获取环境变量接口数据,是通过原生回调函数异步回传的,为了保证环境变量获取后才能执行下一步的H5 http数据请求。因此数据请求需要在原生接口的回调函数里去执行。

1.2.2 现有技术一的缺点

当有多条H5数据请求时,每一条H5 数据请求都需要在原生回调函数里去执行,才能保证环境变量的正确性,会造成原生接口的频繁调用,甚者会造成页面卡顿、app闪退等现象。

  1. 本发明技术方案的详细阐述(发明内容)

2.1 本发明所要解决的技术问题(发明目的)

针对现有技术的不足,本发明提供一种一次同步与多次异步结合调用的一种数据请求方法。

2.2 本发明提供的完整技术方案(发明方案)

由于现在小程序开发框架uniapp缓存存储,存在失效的问题,为了数据安全存储,将用户修改的环境变量数据,存储在app端,在h5页面通过调用接口获取app端的缓存环境变量数据。

小程序调用app接口,app返回信息给小程序,由于app执行业务逻辑的线程与小程序执行调用的的线程不在同一个线程上,这个通讯过程天生异步的,无法做到同步,因此

如果不做到同步,小程序里的每一个请求,都需要有环境变量env值才能获取IP地址,才能进行下一步的数据网络请求服务。因而,因此,H5小程序向服务器发出的每一条数据请求之前,均需调用一次SendGetAppInfo接口以获取IP地址,

这会造成app接口的频繁调用,使得app接口(SendGetAppInfo)被频繁调用,进而容易造成页面卡顿、app闪退等现象页面卡顿,甚至app闪退等现象

为了避免这种现象发生,在本提案中,H5小程序端,对app的异步接口SendGetAppInfo进行同步封装(promise),让app返回结果事件,最终与H5小程序调用事件在同一线程上执行,并同步获取环境env值后,再执行数据网络请求服务。同时,将同步获取环境env值存储为全局变量,从而,当H5小程序多次向服务器发出数据请求时,可直接使用存储的全局变量,而无需向app重新请求环境变量env值。

请注意:本提案中的异步是指异步接口SendGetAppInfo为异步,同步则是指H5小程序调用SendGetAppInfo事件与获取环境env值同步。也就是说,通过promise对象将异步接口SendGetAppInfo进行同步封装, 在promise封装对象中,将同步和异步的方法相结合,提高了获取环境env值的准确性。

    数据网络请求服务又是一个耗时的操作,如果小程序数据请求继续使用同步获取数据,每一条请求又要等着结果出来,再往下执行,那一个页面多条数据请求就需要很长时间,页面就会出现加载慢,闪跳等效果,尤其我们的首页是视频页,体验会非常差。

于是,小程序从app接口同步获取环境env值后,又改为异步网络数据请求方式[Ydf1] 。

通过同步与异步的结合,完成app与小程序之间的异步通讯变为同步获取数据,到小程序与服务器的异步获取数据。[Ydf2] 

解决app与小程序端无法同步通讯的问题,以及保证下一步小程序与服务器的正确IP地址请求。

具体代码实现如下:

定义一个async函数,先调用原生接口,并在原生获取环境变量接口方法前添加await命令,第一次同步调用后全局存储环境变量值,最后返回H5 http异步数据请求Promise对象。参考代码如下:

import store from '../store/index'

import { refreshTokenRequest } from '../api';

import {getLoginInfoFromApp, saveLoginInfoToApp} from '../utils/loginInfo'

let tinyVersion = '2021080303';  // 全局设置版本号,供获取app信息的接口使用

let gdomain = 'i.supor.com';

store.commit('SET_TINY_VERSION', tinyVersion);

let requests = []

let lockRefreshTokenStatus = false

const commonPath = '/supor-food-oss';

function getEnvAsync[周美娜3] () {

  return new Promise((resolve, reject) => {[周美娜4] 

    my.call('sendGetAppInfo', {  // 根据app信息的接口判断当前所处环境

      time: Date.now(),

      tinyVersion: tinyVersion[周美娜5] 

    }, res => {

        switch (res.server) {

          case 0:

            gdomain = 'i.supor.com';

            store.commit('SET_G_DOMAIN', gdomain);

            store.commit('SET_ENV_SAVE', {path: gdomain, desc: '当前环境为苏泊尔正式环境', protocol: 'https://'});

            break;

          case 1:

            gdomain = 'aiot-saas.t.supor.com';

            store.commit('SET_G_DOMAIN', gdomain);

            store.commit('SET_ENV_SAVE', {path: gdomain, desc: '当前环境为苏泊尔验证环境', protocol: 'https://'});

            break;

          case 2:

            gdomain = 'siot-saas.t.supor.com';

            store.commit('SET_G_DOMAIN', gdomain);

            store.commit('SET_ENV_SAVE', {path: gdomain, desc: '当前环境为苏泊尔测试环境', protocol: 'https://'});

            break;

          default:

            gdomain = 'i.supor.com';

            store.commit('SET_G_DOMAIN', gdomain);

            store.commit('SET_ENV_SAVE', {path: gdomain, desc: '当前环境为苏泊尔正式环境', protocol: 'https://'});

            break;

        }[周美娜6] 

        // 同步获取token信息

        if(res.getInfo && typeof res.getInfo === 'string'){

            let getInfo = res.getInfo;

            getInfo = JSON.parse(getInfo);

            if (typeof getInfo === 'object') {

                store.commit('SET_TOKEN', getInfo.token)

                store.commit('SET_USER_INFO', getInfo.userInfo)

                uni.setStorageSync('userInfo', getInfo.userInfo)[周美娜7] 

            }

        }

        // 更新是否支持nfc

        store.commit('updateAppInfo',res);

      resolve(res)[周美娜8] [周美娜9] 

    })[周美娜10] 

  })

}

export default async function uniRequest(param = {}) {[周美娜11] 

    if(store.state.gDomain && store.state.envSave){

      //gDomain 值已经存在,并与缓存值相同,不做处理

    } else {

      await getEnvAsync();[周美娜12] 

    }[周美娜13] 

    let { url, method, data, contentType } = param;

    data = {

      // 其他公共参数

      ...data

    };

    url = `${store.state.envSave.protocol}${store.state.envSave.path}` + commonPath + url;

              let pattern = new RegExp('https://')

    if(!pattern.test(url)) {

          url = `https://${gdomain}` + commonPath + url;

    }[周美娜14] 

    method = method || "GET";

    let header = {};

    header['content-type'] = contentType || 'application/json';

    let token = store.state.user.token

    let getInfo

    if (!token && param.url!="/bossTUser/mobilelogin") {

      await getLoginInfoFromApp().then(res=>{

          getInfo = res.getInfo;

          if (getInfo && typeof getInfo === 'string') {

              getInfo = JSON.parse(getInfo)

          }

          if (typeof getInfo === 'object' && getInfo) {

              token = getInfo.token

              store.commit('SET_TOKEN', token)

              store.commit('SET_USER_INFO', getInfo.userInfo)

              uni.setStorageSync('userInfo', getInfo.userInfo)

          }

      })

    }

    if (token) {

      header['Authorization'] = token

    }

    let showSelfMsg = data.showSelfMsg || false // 是否由组件自己决定消息提示

    return new Promise((resolve, reject) => {

      uni.request({

        url,

        method,

        data,

        header,

        timeout: 10000,

        success: function(res) {

          let { statusCode, data } = res;

          console.log(url + ' res', res)

          data = data || {}

          if (statusCode === 200) {

            if (data.status === 4005 || data.status === 1010) {

              reject(data)

            } else {

              resolve(data);

            }

          } else {

            reject(data)

          }

        },[周美娜15] 

        fail: function(err) {

          const {data = {message:'网络错误,请稍后重试。'}} = err;

          const {message='网络错误,请稍后重试。'} = data;

          if(err.errMsg.indexOf("request:fail")!= -1 && err.errMsg.indexOf("timed out") != -1){

            store.commit('SET_NETWORK_TYPE', "none");

            reject && reject(data);

            return

          }

          if(data.status === 40102) {

            let lockLogin = store.state.user.lockLogin

            if (!lockLogin) {

              store.commit('SET_LOCK_LOGIN_STATUS', true)

              setTimeout(() => {

                store.commit('SET_LOCK_LOGIN_STATUS', false)

              }, 5000)

              // 请求一键登录

              store.dispatch('showOneClickLoginPage')

            }

            reject && reject(data);

          } else if (data.status === 40101) {

            refreshToken(token, {

              resolve,

              reject,

              param

            })

          } else {

            reject && reject(data);

          }

        }

      });

    });

  }

2.3 本发明技术方案带来的有益效果

第一次进入应用同步调用原生接口,获取环境变量后进行全局存储,只需要调用一次原生接口,保证下一步的每条H5 http数据请求正确,由于H5 http数据请求异步调用,多条请求时不会阻塞进程,加快执行速度,提升用户的体验感。

  1. 本发明的技术关键点和欲保护点是什么?

通过一次同步调用原生接口,多次异步调用H5 http数据请求,加快应用执行速度,提升用户的体验感。


 [Ydf1]这里的异步是指H5小程序与服务器之间的数据请求吗??

原来的话,H5小程序与服务器之间的数据请求是同步的??

 [Ydf2]同上批注

 [周美娜3]封装了一个H5小程序的调用方法,此处只是声明方法

 [周美娜4]返回一个异步操作对象promise,先命名为a

 [周美娜5]调用APP接口时传的参数,为时间戳和版本号

 [周美娜6]这里全局存储环境变量

 [周美娜7]这里全局存储token和用户信息

 [周美娜8]res参数为APP接口异步回调函数参数,即返回的数据,业务逻辑需要在此回调函数里面执行,否则拿不到需要的缓存数据。

获取的返回对象res,包含server,token ,userInfo等用户信息,一一进行H5小程序全局,存储在内存中,供其它H5页面,其它业务使用

 [周美娜9]异步加载成功后的返回数据,也就是promise对象异步操作成功后,通知调用他的方法。遇到resolve方法,调用者才知道此异步请求完成,对下面的awiat有用处

 [周美娜10]SendGetAppInfo是APP封装的事件调用接口,供H5小程序调用,获取APP缓存数据,包括环境变量地址server,token ,userInfo等用户信息

 [周美娜11]如果引入此js文件,默认导出的方法,uniRequest静态方法声明

 [周美娜12]Await命令是保证异步操作获取结果后才会执行下面的业务代码,而获取的结果就是getEnyAsync方法里的resolve方法返回值,但此处我们没有拿返回值,只是保证执行到resolve里就行了,说明resolve上面的业务逻辑都已经执行过了,也就是以上我说过的全部保存环境变量,token, userinfo等信息

 [周美娜13]如果全局环境变量有值不做任何处理,如果为空,调用上面声明过得getEnyAsync方法,调用此方法后,由于该方法返回一个异步请求对象promise , 此前我命名为a,会立即执行内部的(立即执行是由promise对象内部机制而来的),APP事件调用,APP事件调用只能异步返回数据,返回的promise对象也是一个异步操作,也就是调用getEnyAsync方法后只能异步返回数据,但是加上await后就将promise对象(a)的异步返回操作变成同步返回,对象a同时也会对内部的getEnyAsync方法调用处理成同步数据返回

 [周美娜14] [周美娜14]这里是对以下需要用到的url请求地址的组合,除了ip,还有路径等信息

 [周美娜15]此js文件导出的uniRequest方法,也是返回一个异步请求对象promise(将它命名为b),当其它页面调用uniRequest方法时,异步操作对象b就会执行内部的http请求,也就是h5向服务器的http数据请求,此请求的url地址,也就是请求的api地址包括环境变量(i.supor.com)等数据,是由异步操作对象a提供

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值