2023-02-21 22:34:08 +08:00

5.6 KiB
Raw Blame History

双线程架构

小程序的架构模型有别与传统 web 单线程架构,小程序为双线程架构。

微信小程序的渲染层与逻辑层分别由两个线程管理,渲染层的界面使用 webview 进行渲染;逻辑层采用 JSCore运行JavaScript代码。这里先看一下小程序的架构图。

image-20230214165008721

可以从图中看出,由于渲染层与逻辑层分开,一个小程序有多个界面,所以渲染层对应存在多个webview。这两个线程之间由Native层进行统一处理。无论是线程之间的通讯、数据的传递、网络请求都由Native层做转发。

首先,我们来解释一下什么是webview

平常我们浏览网页都是在浏览器中,可以想象webview是一个嵌入式的浏览器,是嵌入在原生应用中的。webview 用来展示网页的 view 组件,该组件是你运行自己的浏览器或者在你的线程中展示线上内容的基础。使用 webkit 渲染引擎来展示,并且支持前进后退、浏览历史、放大缩小、等更多功能。

简单来说 webview 是手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装的一个组件。不过没有提供地址栏和导航栏,只是单纯的展示一个网页界面。

因此,微信小程序本质上是一个 Hybrid 应用。

简单回忆一下当前移动端应用的三种模式:

  • 原生应用react native
  • WebAppHTML、CSS、JS
  • Hybrid 应用uniapp、微信小程序

那么,这里采用双线程的好处有哪些呢?在我看来,至少有如下几个点的好处:

  • 避免单线程阻塞问题
  • 多个webview更接近于原生应用的体验
  • 依赖Natvie层做转发,逻辑层与渲染层更加专注于自身的责任

避免单线程阻塞问题

我们知道,浏览器在渲染页面时,靠的是渲染线程进行渲染,所有的活儿都依赖于这个单线程,因此页面的渲染和 JS 的执行是互斥的。

<button id="btn">阻塞5秒</button>
<div class="one"></div>
<div class="two"></div>
div {
  width: 100px;
  height: 100px;
  background-color: red;
  border-radius: 50%;
}
.one{
  animation: move1 5s infinite alternate;
}
.two{
  background-color:blue;
  position: absolute;
  left: 10px;
  top: 150px;
  animation: move2 5s infinite alternate;
}
@keyframes move1 {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(500px);
  }
}
@keyframes move2 {
  0% {
    left: 10px;
  }
  100% {
    left: 500px;
  }
}
function delay(duration) {
  var start = Date.now();
  while (Date.now() - start < duration) {}
}
btn.onclick = function () {
  delay(5000);
};

在上面的示例中,一旦我们执行耗时的 JS 操作,那么小球移动的渲染工作就会被搁置。

但是在小程序中就不存在这个现象,因为它并非像 Web 那样单线程导致 JS 的执行会阻塞页面的渲染。在小程序中,即便执行耗时的 JS 操作,页面仍然能够正常的渲染,不被阻塞。

<button bindtap="handletap">阻塞</button>
<view class="one"></view>
<view class="two"></view>
view {
  width: 100px;
  height: 100px;
  background-color: red;
  border-radius: 50%;
}

.one {
  animation: move1 5s infinite alternate;
}

.two {
  background-color: blue;
  position: absolute;
  left: 0px;
  top: 150px;
  animation: move2 5s infinite alternate;
}

@keyframes move1 {
  0% {
    transform: translateX(0);
  }

  100% {
    transform: translateX(250px);
  }
}

@keyframes move2 {
  0% {
    left: 0px;
  }

  100% {
    left: 250px;
  }
}
Page({
  delay(duration){
    console.log("阻塞开始");
    var start = Date.now();
    while (Date.now() - start < duration) {}
    console.log("阻塞结束");
  },
  handletap(){
    this.delay(5000);
  }
})

多个webview更接近于原生应用的体验

在浏览器的单页应用中,渲染页面是通过路由识别随后动态将页面(组件)挂载到root节点中去,如果单页面应用打开一个新的页面,需要先卸载掉当前页面结构,并且重新渲染。

但是原生APP并不是这个样子比较明显的特征为从页面右侧向左划入一个新的页面并且我们可以同时看到两个页面。

image-20230214203712804

多页面应用就很好达到这个效果,新页面直接滑动出来并且覆盖在旧页面上即可,这也是小程序现在所做的形式。多个webview能够加接近原生应用APP的用户体验。

依赖Natvie层做转发,逻辑层与渲染层更加专注于自身的责任

双线程的好处不仅仅是一分为二而已,还有强大的Native层做背后支撑。

Native层除了做一些资源的动态注入,还负责着很多的事情,请求的转发,离线存储,组件渲染等等。界面主要由成熟的 Web 技术渲染辅之以大量的接口提供丰富的客户端原生能力。同时每个小程序页面都是用不同的WebView去渲染这样可以提供更好的交互体验更贴近原生体验也避免了单个WebView的任务过于繁重。

有了Native层这么一个靠山后,让逻辑层与渲染层更加专注于自身的责任。

课后阅读官方文档:


-EOF-