这篇文章故意具有挑战性、两极化和发人深省的特点。它涵盖了很多你很可能不知道的新鲜内容和想法。
1. 绪论
我将尽力创造一个连贯的逻辑论证链,你可以按照它来了解前端开发应该如何运作。
我也会尽量保持这篇博文的简单性,以便 "非开发人员 "大多能够跟上。
2. 一台电脑或智能手机上有多少个内核?
你们都见过像这样的CPU的图片。
例如,如果你使用的是Mac,你可以点击左上角的苹果图标,然后点击 "About This Mac",它将显示类似的内容。
处理器 3,2 GHz 8核英特尔至强W处理器 |
一部iPhone有6个内核。
每台电脑或智能手机都有几个核心可用。
这意味着你可以并行地运行多个线程。
你会只用一个发动机气缸来跑一辆车吗?
如果你的答案是:"当然不是!"。这将是非常缓慢的!",那么你应该仔细阅读这篇文章。
3. 一个浏览器使用多少个内核?
就其本身而言,浏览器将在每个标签/窗口中只使用一个内核。
意思是:你的Angular或React应用程序看起来像这样。
你的应用程序中运行的JavaScript任务越多,它的速度就越慢。最糟糕的情况是UI完全冻结,你的一个核心处于100%的状态,而其他所有的核心都完全闲置。
这根本就不具有可扩展性。
[题外话】如果你正在创建简单、小型和相当静态的网站或应用程序,这种设置就足够了。
4. Web Worker API
Web Workers API - Web APIs | MDN
Web Workers使得在独立于主执行线程的后台线程中运行脚本操作成为可能...
developer.mozilla.org |
Web Workers 使得在一个独立于 Web 应用程序的主执行线程的后台线程中运行脚本操作成为可能。这样做的好处是,可以在一个单独的线程中进行费力的处理,使主线程(通常是 UI)的运行不会被阻塞/减慢。
Web Worker - 维基百科 zh.wikipedia.org |
W3C和WHATWG设想Web工作者是长期运行的脚本,不会被响应点击或其他用户交互的脚本所打断。让这样的工作者不被用户活动打断,应该可以让网页在后台运行长任务的同时保持响应性。
Worker 最简单的用途是在不中断用户界面的情况下执行一项计算量大的任务。
因此,使用工作者,我们实际上可以并行使用多个核心,结束这种可扩展性的噩梦。
让下面这段话真正沉淀下来。
Worker最简单的用途是在不中断用户界面的情况下执行一项计算量大的任务。
这导致了一个问题。
"什么是最昂贵的任务?”
答案很简单:UI框架或库本身,以及我们用它构建的应用程序。
这就引出了一个想法。让我们把所有能移出主线程的东西都移出来,这样这个线程就能纯粹地专注于它要做的事情:操作DOM。
如果你的应用程序不再在主系统中运行,那么就没有什么东西可以减缓或阻止你的用户界面或产生内存泄漏。
这种想法正导致以下概念。
5. 一个应用Worker是主要的行为者范式
为了解决这个性能瓶颈,我们希望让主线程尽可能地空闲下来,这样它们就可以完全专注于渲染/动态操作DOM。
现在可能发生的最坏情况是,你的应用程序工作者会放慢速度,而这个核心以100%的速度运行。然而,这不会影响你的用户界面(渲染线程→主线程)。
对于单页应用程序(SPA)来说,可能是最好的解决方案,看起来像这样。
为了防止应用程序Worker处理过多的逻辑,我们可以选择使用虚拟 DOM 工作器,在那里计算状态转换之间的延迟更新。对于具有相当空闲的应用Worker的应用程序,你可以选择直接在应用Worker内部运行虚拟DOM引擎来代替。
我们还可以使用一个数据Worker。如果我们有一个远程数据存储,并希望在本地对数据进行排序/分组/过滤,这些计算可以在那里进行。
这篇博文介绍了如何在保持相同的 API 的情况下使Worker的使用成为可有可无的。
JavaScript开发。制作一个可供选择的Web Worker。
如果你有很多与JavaScript相关的逻辑在主线程或Web Worker内运行,这就很有意义了。
6. Worker可以访问DOM吗?
在WorkerGlobalScope里面,window和window.document是未定义的。
意思是:你根本无法直接访问真正的DOM。
因此,我们在这里基本上有两个选择。
选项 1 是在Worker内部重新创建整个 DOM API。在我看来,这是个坏主意。Worker不了解 DOM 是有原因的,而且有大量的逻辑在频繁变化。DOM OPs 变得不同步,如果你依次触发了很多,就会导致大量的 Worker postMessages。唯一的好处是,你可以像以前一样继续写你的应用程序,这是值得怀疑的。我将在后面介绍如何做得更好。
实际上,有一个项目正是这样做的。
GitHub - ampproject/worker-dom: 你所知道的相同的DOM API和框架,但在一个Web Worker中。
更聪明的做法是选项2:坚持Worker不应该知道真正的DOM的概念。
这使得使用虚拟DOM成为绝对必要的。
在社交媒体上阅读时,我经常看到类似 "vdom is bad!"这样的帖子,很频繁。
这根本不是真的。这在很大程度上取决于它是如何被实施的。
Angular和React的主要障碍是基于xml或JSX的模板。这些家伙需要被转换为我们可以使用的数据结构。
JavaScript既不快,也不是为解析字符串而生。
解析模板的成本很高,甚至服务器端渲染(SSR)又开始流行。我在20年前就去过那里,创建了一个基于PHP的CMS,生成html输出文件。
你可以说,今天有了云,可以处理更多的客户端连接,但富/胖/厚客户端的概念仍然完全有意义。
7. 是否有一个例外,Worker可以访问DOM?
实际上有一个。
OffscreenCanvas - Web APIs | MDN
OffscreenCanvas接口提供了一个可以在屏幕外渲染的画布。它在窗口和屏幕外都可以使用。 |
Worker可以接收 Canvas DOM节点的所有权。
这在Chromium中已经运行得很好了,Safari(Webkit)和Firefox正在积极实施。这可能还需要6个月的时间,所以这是2022年的一个话题。
8. 如何以一种聪明的方式创建虚拟DOM?
虽然JavaScript不擅长解析字符串,但它擅长处理嵌套的对象/阵列结构。这种格式有一个名字,你肯定很熟悉。JSON。
如果我们坚持使用基于JSON的vdom语法,就不需要在你的用户界面中反复进行昂贵的模板解析,甚至不需要将这部分移到构建步骤中。
这无疑在某种程度上类似于直接使用JSX输出的工作。
做得好的话,虚拟DOM里面没有变量、if/else语句、绑定、方法、循环或任何形式的逻辑。你永远不会看到有1000多行代码的模板(看Angular)。
使用程序化的方法,你将在属于它的地方使用逻辑:在JavaScript内部。例如,在创建一个列表时,你可以先创建一个骨架的Vdom,一旦数据存储被加载,就在记录上进行迭代,并在运行中创建新的虚拟DOM节点。
这个概念允许我们在运行时从根本上改变一个组件的Vdom。是的,在一个组件被安装之前和之后,改变它的vdom的工作方式是完全一样的。
- 实现无限滚动或其他高级功能变得很容易。
- 你可以在这里找到更多的投入。
- 您使用基于JSON的虚拟DOM的好处。
- 基于JSON的虚拟DOM的新格式化概念。
虽然程序化的方法对低级别的vdom OPs来说是有意义的,但我们肯定更喜欢用声明式的方法来创建我们的应用程序。
为了实现这两点,我们唯一需要做的就是在vdom上面增加一个声明性的抽象层:组件树。
意思是:你只在创建你的组件类时使用vdom。对于创建应用程序,你可以只坚持使用组件树。
9. UI开发可以直接在浏览器中进行吗?
当React在5到8年前开始流行的时候,浏览器在支持最新的ECMAScript功能方面的状况很糟糕。
例如,没有对类(ES6)或JS模块的支持。
在这一点上,将UI开发转移到node中是完全合理的。
意思是:你可以使用最新的语言功能,并以一个构建步骤为代价,将你的代码编译/转译成浏览器能够理解的Javascript。
浏览器供应商在追赶方面做得很好。今天,许多闪亮的新功能都可以直接使用,而且大多数第三阶段的建议确实可以立即实施。
在Worker范围内,JS模块在Chromium内工作正常。Webkit(Safari)也完成了实现,但它仍然限于Safari技术预览版。Mozilla(火狐)正在积极地推动它。
我们可以肯定地认为,全面支持在2022年准备就绪。
构建步骤很昂贵,对于UI库或框架的开发模式来说,应该不再需要。
其优势是显而易见的。
- JavaScript是为了成为唯一能被浏览器引擎理解的编程语言。
- 以浏览器无法理解的方式编写JS,感觉就是错误的。
- 通过将UI开发带回浏览器,我们可以调试我们的真实代码,而不需要任何形式的构建/转译或使用源代码地图。
- 我们不需要热模块的替换。
特别是创建和调试代码将再次成为一种乐趣,因为我们可以确保没有外部因素导致的错误。
像webpack这样的工具肯定还是需要的,以创造地区/生产的输出。然而,它们将是构建工具,而不是运行时环境。
从node到deno的转换将进一步促进这一点。CommonJS将迟早消亡。一旦deno有了一个包管理器,越来越多的包将使用可以在浏览器中运行的语法(例如,不使用裸模块指定符→导入无效的路径和没有文件名扩展)。
10. TypeScript有前途吗?
这一条可能是本文中最有争议的部分。JS社区一分为二:有些人喜欢使用TS,而有些人则拒绝碰它。期待大家的讨论。
我的意见。
现在,当在node中开发UI,并且有一个必要的构建/转译步骤时,使用TS就可以了。
一旦UI开发重新进入浏览器,这种情况将发生根本性的改变。
你会为使用TS而设置一个完整的构建步骤吗?
在这一点上,它变得太昂贵了。
问题是。TS不是一个网络标准。目前还没有计划在浏览器中实施它。
历史已经多次告诉我们,不基于网络标准的网络技术会发生什么:它们会在某个时刻消失。MS Silverlight就是一个完美的例子。
一般来说,类型检查是个好东西。主要问题是Angular和React没有使用基于JSDoc的注释,而JSDoc可以让IDE在写代码时给你发出警告。
实际上,甚至有可能使用基于JSDoc的评论来 "伪造 "TS。
如何在JSDoc注释中编写TypeScript接口
这绝对是一个选择,我们可以讨论。
如果你真的想在你的编程语言中直接进行类型检查,并且不关心构建步骤,那么Dart2是不是更适合?
Dart2完全支持Worker,所以我们也可以让Worker的设置在那里运行。在移动方面的优势包括AOT编译。
11. React有什么问题?
公平地说:在React之前,有JQuery。当React开始流行时,这是一个很大的改进,React是第一个使虚拟DOM流行的库。
那么,为什么我们不应该在2022年使用React呢?
- React在主线程内运行。
- React的代码库是基于CommonJS的→没有构建步骤,它不能在浏览器内运行。
- 没有JSDoc的评论。
- JSX模板的解析成本很高。甚至还有像Svelte这样的编译器来把它移到服务器端。
- React并没有暴露出一个核心。所有的东西都扩展了Component,这一点都没有意义。
- 状态管理无缘无故地太难了。
- render()方法无疑是有问题的。
让我更深入地解释一下这个问题:要防止状态变化触发渲染,肯定是很复杂的。如果一个React组件包含子组件(render()里面的自定义标签),在你没有仔细使用key的情况下,新的实例会被创建。
重新创建Component实例使函数式编程流行起来,因为创建类实例的频率超过了必要的范围,而且在你自己的Component实现中的内存泄漏会造成伤害。
如果你有很多状态道具,例如影响项目的位置,你将需要在你的JSX中添加相当多的逻辑。
React只是一个库,而不是一个框架。意思是说。组件几乎是里面的全部内容。没有逻辑上的层次链,比如。
core.Base -> component.Base -> button.Base -> tab.header.Button
一旦解决了render()的疯狂,你就可以为你想创建的东西挑选最合适的基类。例如,一个容器有一个vdom对象,它包含对其子项的vdom对象的引用。然后,我们可以改变子组件的vdom,而不需要重新创建它们基于JS的实例。
在这一点上,状态管理变得微不足道,我们甚至不需要钩子。特别是在确保对vdom引擎最多有一次调用的情况下,并行改变许多配置是关键。
12. 多窗口应用程序
将Worker的设置换成使用SharedWorkers,可以选择性地增强这一概念。
这使我们能够在不同的浏览器窗口中移动整个组件树,同时保持其JS实例的位置。
多窗口状态管理,不需要后台。
可以进行跨窗口拖放。
13. 我们是否需要自己实现工人的设置?
独自实施所有提到的想法简直要花上几年时间。
你很幸运,我已经为你做了。生态系统内有超过12,000个提交,完全由MIT授权。
GitHub - neomjs/neo:应用工作者驱动的前端框架。
这包括一个远程方法访问API,使你能够通过承诺(消息传递之上的抽象层)直接调用不同工作者或主的方法。
大量的组件已经到位,还有控制器、视图模型、应用程序和其他实用类。
你不需要任何第三方库来支持像MVVM、Observable和其他许多架构设计模式。
尤其是状态管理是非常容易的(提示:一个类的配置系统)。
CLI是先进的:你可以用一个单行字创建一个新的应用程序(工作区):npx neo-app 。我们甚至可以得到跨应用的分割块,所以在把多个应用放在一个页面上时,几乎没有开销。
14. 最后的想法
其实你不必等到2022年,你现在就可以使用这些想法,让你的前端开发更上一层楼。一些公司和开发人员已经在做了,并且正在利用他们的先机将新技术转化为商业优势。
neo.mjs被提名为 "最令人兴奋的技术应用"。
大多数开发者仍然不知道neo.mjs项目的存在,这让人很无奈。
我很想看到有人在这些概念上证明我是错的。
要做到这一点,你将需要创建你的第一个基于neo的PoC应用。
在这种情况下,我希望能审查你的代码。
对于在运行时的动态DOM操作,neo是最快的选择。特别是当它涉及到大型和复杂的应用程序时。
15. 如何开始?
我刚刚创建了一个关于如何使用这项技术实际建立一个应用程序的教程。
定义一个web4.0应用为多线程的应用。