小程序的一些小知识总结

35次阅读

共计 2715 个字符,预计需要花费 7 分钟才能阅读完成。

小程序很多方法都是异步的原因

刚接触小程序的时候,发现很多微信提供的 api 都是异步的,如路由跳转,设置和读取缓存,还有获取节点信息等微信的 api,都是异步的,需要传入回调函数才能获得结果,在我们正常的前端开发中,这些都不是异步的,当时很奇怪为什么是这样的,最近看了微信的一个开发教程之后,总算是明白了。微信小程序开发教程

小程序的底层架构是双线程模式,逻辑层和渲染层是分开的两个线程,渲染层指的就是渲染 wxml 和 wxss,逻辑层指的是执行 js 文件,两个线程分开运行,通过微信客户端进行通信,调用微信的 api 的时候其实就是执行 js 的线程和微信客户端通信
下图是微信官方文档里渲染页面的一个流程图

注意事项:
上述说了,小程序的渲染层和逻辑层是分开的两个线程,执行 js 逻辑的只有一个线程,所以在 js 里声明了的函数,只要有调用,就算页面卸载了,最终都会执行,所以要注意的是,一些 interval,或者一些注册的其他函数,如果不想在页面离开后继续执行的话,在页面卸载的时候要注销掉。

发布和订阅模式

先补充一个知识点:在小程序的 appjs 的 onLaunch 里,给全局变量 wx 添加的属性,是全局有效的,能在其他页面中调用,比如:

onLaunch: function () {
    wx.aaa = '123456'; 
    wx.bbb = function () { console.log('541521') }
}


onLoad: function () {console.log(wx.aaa);
    wx.bbb();}

之前对发布和订阅一直没什么概念,但是多学点东西总没坏处,近期自己花了点时间专门看了一下,大概明白了一点。

订阅:订阅就是在某个地方注册一个自定义的事件,供其他地方调用
发布:触发已经订阅的函数

下面是我写的一个方法,可能会有一些 bug,但是目前没有发现,要是有问题的话欢迎交流一下


var MyEvent = (function () {
  // 声明方法
  var pub, sub, remove;

  // 订阅缓存记录
  var subCache = {};
  // 发布缓存记录
  var pubCache = {};
  // 参数缓存
  var paramCache = {};

  // 订阅事件
  sub = function (key, fn) {if (!subCache[key]) {subCache[key] = [];}
    // 添加到订阅缓存中
    subCache[key].push(fn);
    // 如果有发布记录,则直接执行函数
    if (pubCache[key]) {if (paramCache[key]) {fn.apply(null, paramCache[key]);
      } else {fn.apply(null);
      }
      pubCache[key] = undefined;
    }
  };
  pub = function () {var key = Array.prototype.shift.call(arguments);
    var fns = subCache[key];
    // 没有订阅过,则将参数缓存,待订阅的时候直接执行
    if (!fns || fns.length === 0) {pubCache[key] = true;
      paramCache[key] = Array.prototype.slice.call(arguments, 0);
      return;
    }
    // 有订阅记录,则直接执行
    for (let fn of fns) {fn.apply(null, arguments);
    }
  };
  remove = function (key) {
    // 把所有的缓存全部清除
    subCache[key] = undefined;
    pubCache[key] = undefined;
    paramCache[key] = undefined;
  };
  return {
    pub: pub,
    sub: sub,
    remove: remove
  };
})();

module.exports = MyEvent;

使用方法如下:
在 appjs 里引入 MyEvent,并挂载在 wx 对象上

App({onLaunch: function () {const MyEvent = require('myEvent 的路径');
    wx.myEvent = MyEvent;
  }
})

在其中页面页面 1 的 onShow 里订阅 test1 事件,发布 test2 事件

onLoad: function(){wx.myEvent.sub('test1', function () {console.log('test1');
    });
},
onShow: function () {wx.myEvent.pub('test2', 'test2' + new Date().getTime());
}

在页面 2 的 onLoad 事件里,发布 test1 事件,订阅 test2 事件

onLoad: function(options) {wx.myEvent.pub('test1');
    wx.myEvent.sub('test2', function(a){console.log(a);
    });
}

一. 在页面 1 的时候,执行了订阅 test1 事件,发布了 test2 事件,但是 test1 没有发布,订阅的事件不会执行,test2 事件没有订阅,也不会执行。

二. 从页面 1 跳转到页面 2,发布了 test1 事件,直接执行之前已经注册好的 test1 事件,订阅 test2 事件,因为有 test2 的发布事件,订阅之后直接执行,结果是打印一次 test1,打印一次 test2。

三. 从页面 2 返回到页面 1,执行 onShow 事件,再次发布 test2 事件,打印一次 test2

四. 从页面 1 到页面 2,发布了 test1 事件,事件 test2 重复订阅了,订阅了两次,打印一次 test1。

五. 从页面 2 返回页面 1,发布 test2,因为 test2 事件订阅了两次,所以打印了两次 test2,所以要注意在不需要的地方把事件注销。

在页面 2 的 onUnload 事件里把事件 test2 注销掉,在从页面 2 回到页面 1 的时候,事件 test2 已经注销了,不会再执行。

onUnload: function() {wx.myEvent.remove('test2');
}

原理和用法说明:
原理:
全局只有一个 wx 对象,将 myEvent 挂载在 wx 上,所以全局也只有一个 wx.myEvent 对象,myEvent 里用到了闭包,订阅的函数和参数都有保存在内存里,所以能实现订阅和发布的功能。
目前事件订阅是用的数组存储,可实现同一个事件订阅多次,如果不需要的话可自行修改成只能订阅一次的方法。
用法:
一般用于跨页面的操作,比如在某个页面订阅某个事件,在另一份页面执行了某项操作之后,发布该事件,会直接执行订阅的事件,实现页面间的一些数据传递。
还有也可用于异步请求,先订阅某个事件,异步请求数据,请求数据回来之后,再发布。

待补充 ……

正文完
 0