let waitRunPreload; //等待预加载方法注册后执行
function rewritePage (){ let cPage = Page
Page = function rebuildPage(options){
if (!options['onLoad']) options['onLoad'] = function () { };
if (!options['onShow']) options['onShow'] = function () { };
if (!options['onHide']) options['onHide'] = function () { };
if (!options['onUnload']) options['onUnload'] = function () { };
const copyOnLoad = options['onLoad'];
options['onLoad'] = function(){
//当前页面是否有注册预加载函数
if(allPagePreloadMap[this.path]){
//预加载函数是否执行
if(allPreloadDateMap[this.path]){
this.setData.call(this,{...allPreloadDateMap[this.path]});
}else{
allPagePreloadMap[this.path].call(this,[...arguments]);
}
}
return copyOnLoad.apply(this,[...arguments])
}
const copyOnShow = options['onShow'];
options['onShow'] = function(){
this.$isBuild = true;
return copyOnShow.apply(this,[...arguments])
}
const copyOnHide= options['onHide'];
options['onHide'] = function(){
this.$isBuild = false;
return copyOnHide.apply(this,[...arguments])
}
const copyOnUnload = options['onUnload'];
options['onUnload'] = function(){
delete allPreloadDateMap[this.path];
return copyOnUnload.apply(this,[...arguments])
}
// 注册页面的预加载方法
if(options['registerPreload']){
// console.log('注册页面的预加载方法',options['path'])
if(!options['path']) {
console.error('注册预加载方法必须同时设置页面路径,同路由跳转url')
}else{
allPagePreloadMap[options['path']] = options['registerPreload'].bind(options);
//检查是否已经有该页面的预加载请求调用被缓存
if(waitRunPreload && waitRunPreload.path == options['path']){
waitRunPreload.run(allPagePreloadMap[options['path']])
waitRunPreload = null;
}
}
}
//封装setData,建议只在预加载方法中使用,如果页面已经创建,数据直接更新到data,否则存储到缓存中
options['$setState'] = function(){
const pageInstance = getCurrentPages()[getCurrentPages().length - 1];
if(pageInstance.route == this.path){
allPreloadDateMap[this.path] = {...allPreloadDateMap[this.path],...arguments[0]}
return pageInstance.setData.apply(pageInstance,[...arguments]);
}else{
allPreloadDateMap[this.path] = {...allPreloadDateMap[this.path],...arguments[0]}
}
}
//预加载页面数据
options['$preload'] = async function(path,data={}){
allPreloadDateMap[path] = {};
//在已经调用下个页面预加载请求但该页面所在分包未加载的情况下,缓存path和参数
if(allPagePreloadMap[path]){
allPagePreloadMap[path](data);
}else{
waitRunPreload = {
path,
run:function (fn){
return fn.call(this,data)
}
}
}
}
this.$route('pages/logs/logs',{},true)
options["$route"] = function (url,data = {},isPreload = false,options = {}){
if(isPreload){
allPreloadDateMap[url] = {};
//在已经调用下个页面预加载请求但该页面所在分包未加载的情况下,缓存path和参数
if(allPagePreloadMap[url]){
allPagePreloadMapurl;
}else{
waitRunPreload = {
path:url,
run:function (fn){
return fn.call(this,data)
}
}
}
}
url = '/'+url;
let query = "";
for(let key in data){
data[key] + '&' + query;
}
url = url + ${query.length?'?'+query:query}
if(getCurrentPages().length>9){
wx.navigateTo({
url,
...options
})
}else{
wx.reLaunch({
url,
...options
})
}
}
return cPage(options);
}
}
rewritePage() </code></pre>
<p>页面A可以自己决定预加载的时机,可以选择任意时候调用this.$preload(页面Bpath,data)方法触发页面B的网络请求,也可以使用this.$route(页面Bpath,data,true)方法,在跳转成功后调用。</p> <p>针对上面提的三个痛点,解决方法如下</p> <h3>痛点1</h3> <p>利用小程序加载过程,缓存所有页面的registerPreload的方法,在页面A调用时候,利用path查找缓存的方法进行调用。</p> <h3>痛点2</h3> <p>因为请求是异步的,可能到了页面B,预加载的请求还没有回来。所以自定义了一个this.$setState方法替换this.setData,并在 registerPreload 方法中使用,在页面B未创建的时候会将Data保存才缓存中,创建完成后,会直接调用this.setData更新到页面。同时在页面B的页面onLoad方法中,会判断 registerPreload 方法是否调用,如果调用,会检查内存中使用是否有请求的数据,有的话会setData到data。</p> <h3>通点3</h3> <p>如果页面B位于分包中,在页面A调用页面B的 registerPreload 方法时候,registerPreload 方法还没有注册到缓存中。解决方案是在调用时候检查缓存中是否已经注册,如果未注册,则缓存调用 registerPreload 的请求,在分包代码加载 页面 registerPreload 注册到缓存时候,检查是否有当前页面的 registerPreload 请求,如果有则立马调用。</p> <p><a href="https://github.com/hspprogrammer/wx-gulp-mini">源码</a>以上都是个人对微信小程序请求预加载的粗浅理解和应用,欢迎各位大佬评论区留言指导交流。</p><!--14-->