Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试官:说说微信小程序的实现原理? #18

Open
linwu-hi opened this issue Jul 30, 2023 · 0 comments
Open

面试官:说说微信小程序的实现原理? #18

linwu-hi opened this issue Jul 30, 2023 · 0 comments

Comments

@linwu-hi
Copy link
Owner

linwu-hi commented Jul 30, 2023

面试官:请你谈谈微信小程序的实现原理?

一、背景

在传统的网页开发中,渲染线程和脚本是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应的原因,因为我们常说的 JS 是单线程的。而微信小程序则选用了 Hybrid 的渲染方式,将视图层和逻辑层分开,实现双线程同时运行。在此模式下,视图层的界面使用 WebView 进行渲染,而逻辑层则在 JSCore 中运行。

image

在小程序中,渲染层主要负责界面渲染相关的任务,并在 WebView 线程里执行。一个小程序可能存在多个界面,所以渲染层存在多个 WebView 线程。而逻辑层则采用 JsCore 线程运行 JS 脚本,执行的都是与小程序业务逻辑有关的代码。

二、通信

在小程序的渲染层,宿主环境会将wxml转化成对应的JS对象。当逻辑层的数据发生变更时,通过宿主环境提供的setData方法,数据就可以从逻辑层传递到渲染层。然后通过对比数据变化前后的差异,将差异应用在原来的Dom树上,从而渲染出正确的视图。

image

例如,用户点击界面上某个按钮,这类反馈需要通知给开发者的逻辑层,以便将对应的处理状态呈现给用户。对于事件的分发处理,微信进行了特殊的处理,将所有的事件拦截后,丢到逻辑层,交给JavaScript进行处理。

image

由于小程序是基于双线程的,因此在视图层和逻辑层之间的任何数据传递都是线程间的通信,会有一定的延时。所以在小程序中,页面更新成了异步操作。异步会使得各部分的运行时序变得复杂一些,逻辑层与渲染层需要有一定的机制保证时序正确,在每个小程序页面的生命周期中,存在着若干次页面数据通信。

image

三、运行机制

小程序启动运行主要有两种情况:

  • 冷启动(重新开始):用户首次打开或者小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动,即为冷启动
  • 热启动:用户已经打开过小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需要将后台态的小程序切换到前台,这个过程就是热启动

需要注意的是:

  1. 小程序没有重启的概念
  2. 当小程序进入后台,客户端会维持一段时间的运行状态,超过一定时间后会被微信主动销毁
  3. 短时间内收到系统两次以上内存警告,也会对小程序进行销毁,这也就为什么一旦页面内存溢出,页面会奔溃的本质原因了

image

当开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。

四、举例说明

以下是一个简单的示例来展示小程序的数据通信过程:

Page({
  data: {
    text: 'Hello, World!'
  },

  changeText: function () {
    this.setData({
      text: 'Hello, OpenAI!'
    });
  },

  onLoad: function () {
    // 页面加载时,打印初始数据
    console.log(this.data.text);
  },

  onReady: function () {
    // 页面初次渲染完成后,改变数据
    this.changeText();
  },

  onShow: function () {
    // 页面显示后,打印改变后的数据
    console.log(this.data.text);
  }
});

在这个示例中,我们首先在Page对象的data属性中定义了初始数据text。当页面加载完成后,我们在onLoad生命周期函数中打印出初始数据。然后在页面初次渲染完成后,我们通过this.setData方法改变数据。最后在页面显示后,我们打印出改变后的数据。

参考资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant