主机参考:VPS测评参考推荐/专注分享VPS服务器优惠信息!若您是商家可以在本站进行投稿,查看详情!此外我们还提供软文收录、PayPal代付、广告赞助等服务,查看详情! |
我们发布的部分优惠活动文章可能存在时效性,购买时建议在本站搜索商家名称可查看相关文章充分了解该商家!若非中文页面可使用Edge浏览器同步翻译!PayPal代付/收录合作 |
本文带你了解微信小程序的双线程模型,说说什么是小程序的双线程模型?为什么小程序使用双线程模型而不是浏览器的线程模型?希望对大家有帮助!
有微信小程序开发经验的朋友应该都知道“双线程模式”的概念。本文简单梳理了一些双线程模型的科普知识,知识面较浅。如有错误,请指正。
我曾经在“小程序云开发”团队工作。在一些外部培训和技术分享中,经常被问到这样一个问题:“微信小程序和Web站点的主要技术区别是什么?”在编程语言和范式上,小程序开发和Web前端开发非常相似(比如都用JavaScript语言,WXML/WXSS,和HTML/CSS非常相似等等。),但并不直接使用原生前端技术。【相关学习推荐:小程序开发教程】
相比网站,微信托管的小程序需要考虑安全、性能等因素,保证小程序不会对微信App本身造成安全隐患,同时尽量做到接近原生应用的性能和用户体验。这也是小程序不直接使用浏览器的线程模型,而要自己弄一套双线程模型的两个主要原因。
什么是小程序的双线程模型?
理解一个新概念或新技术的最好方法就是给它一个参考,所以要理解小程序的线程模型,首先要对浏览器的线程模型有一定的了解。
浏览器有可能是多进程的。每一个前端工程师在刚入行的时候都不止一次被面试官问到“你是怎么理解前端单线程的?”因为前端核心技能之一的JavaScript是单线程的,所以充分了解和掌握JS单线程的运行方式是对一个前端工程师最基本的要求。但是有一个很多初学者很容易陷入的误区:把“JavaScript单线程”误理解为“浏览器单线程”。
其实浏览器内部架构很复杂,但是在处理GUI渲染线程和JavaScript逻辑脚本线程时使用了互斥和阻塞的管理模式,让一些开发者产生了误解。
以Chrome浏览器为例,点击右上角的设置按钮然后进入“更多工具”->:任务管理器会看到一个这样的弹出窗口:
你可以看到Chrome开放了几个进程,包括浏览器进程、网络进程、GPU进程等。这些都是一般流程。请注意,上图中有两个tab流程。Chrome为每个选项卡启动一个独立的渲染器进程。资源(CPU、内存等。)和行为(UI、逻辑等。)彼此之间是不共享的,所以即使一个选项卡崩溃,也不会影响其他选项卡。
在每个tab进程中,浏览器会将不同的作业交给相应的线程,比如GUI渲染线程负责将HTML渲染成可视化UI;JavaScript引擎线程负责解析和运行JavaScript代码逻辑;触发线程负责处理setTimeout/setInterval定时器等。
GUI渲染线程和JavaScript引擎线程是互斥的,JavaScript在执行过程中会阻塞UI渲染。即使脚本执行时间过长,页面也会长时间无响应,然后崩溃。正是这种GUI渲染线程和JavaScript引擎线程之间互斥、阻塞的线程管理,让一些前端开发者认为浏览器是单线程的。
那为什么JavaScript要设计成单线程?
JavaScript的鼻祖只用了10天就创造了这种语言。起初,他的想法是在浏览器中提供一些简单的脚本逻辑来处理用户交互、DOM操作等。,因此在设计中必须遵循两点:
语法简单;
操作机制简单。
语法上,JavaScript借鉴了Java,但是去掉了很多复杂的设置,比如类型声明,模块系统(后面加的)等等。
在运行机制上,JavaScript不像Java那样提供多线程能力,最重要的是避免多线程DOM带来的UI冲突。比如有多个线程同时操作同一个DOM,浏览器如何判断哪个线程是最终UI效果的结果?这是一个经典的线程安全(也称为线程同步)问题。多线程编程领域有很多解决方案,比如添加锁机制,但这带来了更多的复杂性,违背了JavaScript简单易用的设计初衷。
这也解释了为什么GUI渲染线程和JavaScript引擎线程是互斥的:JavaScript代码有权修改DOM。
JavaScript代码执行时,GUI渲染线程会被挂起,然后在JavaScript引擎线程空闲时执行,避免渲染时JavaScript反复修改DOM造成不必要的渲染压力。采用互斥模式等待JavaScript代码执行,可以保证渲染是最终的执行结果。因此,浏览器的空闲时间也成为衡量网站性能的重要指标之一。空闲时间大多意味着JavaScript逻辑不密集,DOM变化频繁。在这种情况下,浏览器可以更加快速流畅地响应用户的交互行为,如下图所示:
后来,HTML5引入了Web Worker来提供多线程执行JavaScript代码的能力。但是,与其他编程语言不同的是,worker线程并不是与主线程并行的,而是Master-Slave多线程模型。
Worker中的JavaScript代码不能操作DOM,所以可以理解为线程安全。记住这一点,这是后面要描述的小程序的双线程模型的重要基础。
那么微信小程序为什么不直接使用浏览器的线程模型呢?这需要从产品和技术两个方面比较小程序和网站的区别。
小程序为什么不用浏览器的线程模型?刚接触小程序开发的时候,经常“嫌弃”它相对于Web的阉割弱化能力,相对于Vue的简单过度的语法。当时我几乎觉得小程序是微信凭借其庞大的用户数量的技术垄断。
但随着对技术和产品理解的深入,我对小程序的态度也发生了变化,从“不喜欢”到推崇,因为在充分了解小程序的产品定位后,我发现在小程序等产品场景下,双线程模式才是最优方案。小程序是一个什么样的产品?
小程序的主机是微信,但是小程序版本的迭代是独立的,升级更新不依赖主机,这和网站是一样的。也就是说,小程序继承了Web的一些优点,但不是Web。目前Web相关的技术已经相当全面,可以承载一些非常大的应用,比如3D地图、游戏等。
小程序的定位是小而美,用完就走。它并不追求微信中所有的Web能力,所以在能力上肯定不如Web。同时具备微信提供的一些原生能力,如原生组件、微信生态系统的系统级和API等。
另外,“小程序-微信”和“网站-浏览器”的关系是不一样的。前者更接近于CodePen、JSFiddler等在线编程平台中每个程序案例(简称案例)与平台的关系。
从技术角度来说,平台的核心考虑之一是在为案件提供足够能力的前提下,保证案件的逻辑不会危及平台的安全。试想一下,如果你能在CodePen上写一个程序来获取CodePen的私人信息,说不定第二天CodePen就会崩溃,开除所有员工。
在这样的产品基调下进行技术选择,接下来就是架构师和程序员的工作了。
以CodePen为例。如果让你设计这样一个编程平台,你会用什么技术?也许您首先想到的是使用iframe,因为您可以在iframe中使用所有的Web功能。实际上,CodePen确实使用iframe来呈现程序的效果,但它并没有将输入的JavaScript代码完全复制到iframe中来运行,而是将代码经过一个编译过程后注入到iframe中。这样做的出发点主要是基于安全考虑,在编译过程中剔除了一些危险代码;其次,它可以支持平台中更多的语言,比如typescript。当然,还有性能。性能是iframe的老生常谈,就不多说了。
所以不仅要用iframe,还要引入额外的JavaScript编译器。CodePen必须确保每种情况下的JavaScript代码都是线程安全的。最基本的就是禁止程序操作CodePen网站的DOM。有两种方法可以实现这一点:
一个是网络工作者;;
另一种是使用影子DOM。
Web Worker是线程安全的,Worker中的JavaScript代码无法获取窗口和文档对象,所以无法操作DOM。另外,由于Worker的线程安全特性,Worker中的代码在运行过程中不会阻塞外层的GUI渲染线程,两者可以并行。
影子DOM是Web组件规范的一部分。将ShadowRoot的模式设置为closed可以禁止获取ShadowRoot节点,这样里面的DOM就不能操作了。
两者相比,Shadow DOM的兼容性比Web Worker差,而且离大规模使用的日期还很远,所以Web Worker的方案更符合实际。
这样就形成了一个简单的双线程模型:工作线程负责计算,结果通过postMessage传递给主线程,主线程负责渲染。
然而,这种模式存在严重的性能问题。Web Worker消耗大量资源,除了计算,与主线程的通信过程也消耗大量性能。
有什么办法可以做到和Web Worker一样的线程安全,同时兼顾用户体验,性能保证好?这是微信小程序采用双线程模式的主要目的。
高效的双线程模型虽然以CodePen等编程平台作为类比,但是小程序和CodePen的技术要求并不完全相同。主要区别在于小程序不需要支持所有的HTML标签,只提供有限数量的UI组件。根据小程序的产品定位,我们可以得出,小程序的主要技术要求可以概括为以下几点。(任何新的技术或架构都是为了解决特定的问题,所以需要了解小程序的主要技术要求。)
限制UI组件类型,只能声明几个指定的组件。
小程序在声明组件时不使用原生HTML标签,只能使用微信提供的几个内置基础组件。当然也可以自定义组件,但也是通过内置的基础组件组合实现的。
保证逻辑线程的安全,不允许直接操作UI组件。
小程序更新UI的方式类似于Vue/React等MVVM框架。JavaScript代码不能直接操作DOM(只是打个比方,其实小程序里没有DOM的概念),而是通过更新状态(setState)来异步更新UI。在这个过程中会用到VDOM和高效的diff算法(这两点不是我们要讨论的,大家可以在课后自己搜索相关资料)。
能够在线更新,不依赖微信
小程序的宿主是微信。如果使用纯原生实现,那么小程序的版本更新必须依赖微信,版本要和微信的代码一起分发,这肯定是不行的。如果是纯Web实现,安全性和性能几乎无法保证。
小程序需要能够像Web一样在云端托管资源,独立更新;同时又能保证足够好的安全性和性能。所以最终小程序采用了混合架构模式:使用Webview渲染UI,使用Web Worker这样的独立线程运行逻辑,也就是双线程模式。
性能需要尽可能提高,以保证用户体验。
前面提到的基于Web Worker的简单双线程模型的性能是一个大问题。小程序的双线程模式,不使用Web Worker子线程,而是独立的“主线程”,可以保证相对较好的性能。
渲染线程和逻辑线程小程序的双线程是指渲染线程和逻辑线程,分别负责渲染UI和执行JavaScript代码。如下图所示:
呈现线程使用Webview来呈现UI。Webview是一个完整的类似浏览器的运行环境,它有运行JavaScript的能力。但是小程序不是把逻辑脚本放到Webview里,而是把逻辑层做成一个和Webview并行的线程,使用客户端提供的JavaScript引擎来运行代码。iOS和Android的JavaScriptCore是腾讯X5内核提供的JsCore环境和IDE工具的nwjs。
逻辑线程是一个只能运行JavaScript的沙盒环境,不提供与DOM操作相关的API。所以它不能直接操作UI,只能通过用setData更新数据来异步更新UI。
事件驱动的通信模式
注意上图中渲染线程和逻辑线程之间的通信。与Vue/React不同的是,小程序的渲染层和逻辑层之间的通信并不是直接在它们之间传递数据或事件,而是由Native作为中间媒介进行转发。
整个过程是一个典型的事件驱动模型:
渲染层(也叫视图层)通过与用户的交互触发特定的事件事件;
然后将事件传递给逻辑层;
逻辑层再通过一系列的逻辑处理、数据请求、接口调用等行为,将处理后的数据data传送给渲染层;
最后,呈现层将数据呈现到可视化UI中。
这种数据驱动的UI模式是前端编程领域备受推崇的编程范式。如果你是一个有5年以上开发经验的前端开发者,那么我相信你刚接触这种模式的时候一定会有一些不适应,因为在此之前,DOM的JavaScript操作几乎是一个“行业规则”,甚至很多前端入门的书籍、博客、教材都是从DOM操作开始的。现在看来,这些真的过时了。
一方面,逻辑和渲染分离的线程划分模式可以保证运行在逻辑线程沙箱中的JavaScript代码是线程安全的;另一方面,渲染线程的计算量很小,保证了对用户交互行为的快速响应,提高了用户体验。
总的来说,相对于浏览器的线程模式,小程序的双线程模式解决或规避了Web worker令人担忧的性能,同时实现了与Web worker相同的线程安全性,从性能和安全性两个方面进行了提升。一般来说,双线程模式是受浏览器现有进程和线程管理模式限制,在小程序特定场景下的一种改进架构方案。
总结在我看来,程序员的核心能力和竞争力不是完全理解某一种语言或框架的API,而是这些语言和框架的底层原理知识。对于一个小程序的开发者来说,解决工作中的技术问题往往是基于底层原理(更直白的说,你找工作面试的时候,没人会问你小程序的语法)。
通过了解小程序双线程模型的背景、设计和通信,希望能对小程序的底层架构有更深入的了解。如果后续工作中有类似的场景,也可以作为参考。当然,理解小程序的双线程模型并不是唯一的目标。在某种程度上,这些知识可以给日常开发工作一些启发,主要表现在:
在保证功能的前提下尽量使用结构简单的UI;
最小化JavaScript逻辑的复杂度;
尽量减少setData的调用频率和承载的数据量。
有关编程的更多信息,请访问:编程视频!!以上是深入分析小程序中双线程模型的详细内容。请多关注主机参考其他相关文章!
这几篇文章你可能也喜欢:
本文由主机参考刊发,转载请注明:深入分析小程序中的双线程模型(微信小程序有两个线程) https://zhujicankao.com/74502.html
评论前必须登录!
注册