在网上查了一下,说是如果多个线程同时修改 DOM ,可能会导致竞态条件和不可预测的结果。但是微信小程序用的就是双线程啊?所以浏览器用单线程最本质的原因是什么?以及微信小程序为什么要使用双线程?

微信小程序的双线程是指渲染层和逻辑层由不同的线程管理。

developers.weixin.qq.com/community/develop/article/doc/0000461093c4d8782ff7cf7d95b413

渲染层两者不都是单线程吗,想另开逻辑线程浏览器也可以用 worker ,worker 不能直接操作 dom

GUI 渲染一般都是单线程的,小程序也是。
chrome 浏览器的 js 执行是在独立线程的,小程序也是。
小程序和 chrome 一样,js 执行完需要改界面也是委托给渲染线程渲染。至少在这层面来说他们没有你说的区别。

我比较好奇为什么浏览器会设计成这样,微信小程序又设计成那样,以及浏览器为什么不设计成微信小程序这样的

GUI 有单独的页面更新和渲染逻辑
windows 上我就遇到过另一个线程修改页面导致控件花屏的

我搜了下网上关于小程序双线程的文章,感觉是说的浏览器和 chrome 之类的现代浏览器是不同的。浏览器那么多,你说的是哪个?

微信小程序的方式只是同一个页面中渲染和逻辑是分离的,UI 层面本质上还是 webview 在绘制,这个 Android 手机上打开调试模式就可以看到页面栈或者 tab 页面都是一个独立的 webview 。

我所了解的除了浏览器渲染,其他像 iOS 原生、Android 原生、Unity 游戏开发都是只能在 UI 线程也称主线程上操作。

最阻碍技术推进的原因肯定是复杂度和收益不成正比。比如本来只通过主线程操作可以进行脏检查来加快一帧数据渲染,但是多线程下面就歇菜了。

小程序的双线程,本质上就是阉割了 webview ,通过他们的框架/IDE/runtime 将逻辑放在他们定制的逻辑线程里执行,然后通过 setData 通知 webview 更新,这么做他们的理由就是内容可控、安全什么的,当然有一定的道理。

所以说小程序所谓的双线程是没有太多技术创新的,因为只是嫁接在 webview 上实现的功能,而且他们的目的也不是技术创新,只是为了实现自身可控的 runtime 。

几乎所有 GUI 渲染都是单线程的,多线程渲染很容易出现死锁、竞争等问题。

多线程带来的问题大于能带来的好处,除非有更好的架构真的能让你的程序有特定的优点。

你别想复杂了,现实生活中画画这个行为就无法多人合作。
你见过有十个画师同时画一张色图吗?
A 画师绘制巨乳的时候,别人就只能去画美腿。
能优化的只有分图层,分模块,这一部分 GPU 级别就已经做了很多优化了。
现实世界做不到的事情,程序上也做不到。代码也是现实世界的映射。

所有的 gui 程序中更新界面的工作都只能交给一个线程

因为一个线程够了

我刚学编程时深入研究过这个问题,不只是浏览器这么做,任何涉及 UI 的框架都是单线程模型,QT, Android ,Swing ,WPF ,MFC 等等等等。结论其实就很简单,也很笼统,就是多线程就是不好的设计,有时候为了加速不得已才引入的多线程。平时开发都是能不多线程就不多线程。

几个链接自己研究去吧

zhuanlan.zhihu.com/p/44639688

flylib.com/books/en/2.558.1/why_are_guis_single_threaded_.html

learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/threading-model?view=netframeworkdesktop-4.8

微信小程序那个问题是为了实现热更新使用了 web 技术,而 webview UI 和 js 都在一个线程,JS 里执行一些耗时逻辑,UI 不就直接卡死了,所以分了双线程 UI 和 逻辑

早期浏览器,例如 IE6 都有单进程的模式的,chromium 改变了这套架构:

blog.chromium.org/2008/09/multi-process-architecture.html
www.reddit.com/r/explainlikeimfive/comments/2xuh8q/eli5why_do_web_browsers_run_multiple_processes/

本质就是 小程序不想让你操作 DOM, 只提供封装后的给你, UI 的实现就可以有私有实现(比如 暴露一些 wx 内部的 API/控件 什么的出去)

浏览器为什么不这么设计: 因为原来没有这样的需求

这里 独立的 JS 线程 就是 个 没有 web api javascript instance (因为所谓的 “多个线程同时修改 DOM ,可能会导致竞态条件和不可预测的结果”,就是 web api 不提供线程安全性),现代 web 浏览器里也是有的,就是 Web Worker ,

只是小程序,的与 UI 线程的通信/交互啊什么的都是封装好了的,Web Worker 里你得自己来

不是有 worker 么,只是没有好用的协程切换工具,相比之下原生安卓的配合 kt 的协程是个不错的设计。在 js 这你只能通过 ipc 来实现 worker 通信。

问题 1:"在网上查了一下,说是如果多个线程同时修改 DOM ,可能会导致竞态条件和不可预测的结果。但是微信小程序用的就是双线程啊?"
回答:微信小程序的双线程指的是逻辑线程和渲染线程,其中逻辑线程一样也是无法直接同步修改 DOM 的,需要通过 bridge 通信的方式告诉渲染线程来操作 DOM 。其实浏览器也可以做类似的事情,就是把逻辑代码放 web worker 来执行(类似小程序的逻辑线程),现在的 js 线程只接收 web worker 传来的信息进行渲染。社区也有人探索类似的方案,比如
github.com/web-perf/react-worker-dom ,就是把 react 搬到 web worker 上运行。

问题 2:“所以浏览器用单线程最本质的原因是什么?”
回答:个人感觉更多是因为早期 JS 就是个脚本语言,主打就是要简单易用,如果引入了多线程会变得更加复杂,当时也没有这个需求。

问题 3:微信小程序为什么要使用双线程?
回答:上面说的 react-worker-dom 虽然类似小程序采用了双线程,但是咋没有流行呢?主要还是因为浏览器的性能瓶颈在 DOM 的渲染上。如果要在浏览器上做一个类似原生应用或微信小程序的页面切换,很容易出现页面切换时卡顿的问题。如果有尝试用过 ionic 来开发 hybrid app ,你会发现页面的切换始终会有存在掉帧的问题,特别是页面 DOM 数量多了。而微信小程序直接每个页面就是新的一个 webview ,交给原生来切换。
另外,客户端那边操作 UI 也必须是在主线程上的,不允许在其他线程直接操作 UI ,客户端为什么更流畅,主要还是因为 JS 本身性能有差距,还有就是 DOM 的渲染性能比原生差很多。记得早起还有人尝试过放弃 DOM ,自己用 canvas 来做一套渲染引擎来优化渲染性能。

微信小程序和 react native 的方案导致了如果直接实现动画,会比较“不跟手”,即存在操作延迟,对于按钮这类交互控件倒是没有啥影响,但滚动的时候就会较为明显,于是微信小程序和 react-native 都各自发明了在 ui 线程里跑代码的方案

感觉明白多了🙏

修改 DOM 和渲染 DOM 是不同的意思。抛开浏览器环境里,考虑一个大型游戏软件,为了提升游戏性能 必然要用到多线程,修改状态的线程当然可以是多个,即使渲染线程只能是一个。

因为 JavaScript 的 web api 里有能直接操作 DOM 的 API