SolidJS 的创造者:JavaScript的创新并没有放缓

362 阅读13分钟

SolidJS的创造者。JavaScript的创新并没有放缓

在Solid标志着其1.0版本发布之际,创建者Ryan Carniato讨论了该框架的起源、最新的JavaScript创新,以及继续推动前端JS性能的必要性。

最近,最有趣的JavaScript框架之一是SolidJS。Solid很有趣,因为它将JSX(React的模板语言)推向了新的方向。它用少量的反应式基元来装饰JSX。它是经过编译的(类似于Svelte)。它将高阶服务分层(如中央存储和事件)。为了稳妥起见,它还加入了全功能的SSR(服务器端渲染)和Suspense。

我和Solid的创建者Ryan Carniato谈了谈他和Solid团队是如何做到这一点的,Solid与行业发展的关系,创新的前端功能(如部分水化、流式SSR和Suspense)是如何实现的,以及是什么促使他不断推动前端JavaScript性能的极限。

Matthew Tyson: 嗨,Ryan,感谢你今天抽出时间来聊天。第一个问题,Solid是一个编译的框架,就像Svelte。你是受Svelte的启发而选择了编译的路线吗?

Ryan Carniato: 不,Svelte直到2019年的V3版本才开始进行核心编译。我们已经有了这个系统,并且在2018年初就已经粉碎了基准。Svelte有一些很酷的想法,把编译做得更进一步,我知道他们的一些决定,但不是最初的方向。

泰森 :我认为前端JavaScript的创新量是惊人的。你能感觉到我们在这种演变中的位置吗?我们是否接近了一个高峰?

Carniato :我认为在原始渲染性能方面,我们已经达到了极限,说实话,这还不够好。这就是为什么这个领域不断发展的原因,我们知道我们可以做得更好。这也是为什么你会看到在其他地方有那么多的研究,以获得每一盎司的性能或改善用户体验。

我已经说了好几年了。这并没有放缓。在一些框架和库中,有一些技术还没有在一些更流行的框架和库中得到应用,而且这些东西还在继续研究和改进。我理解人们希望事情趋于平缓的愿望,从某种意义上说,随着JS框架的成熟,它已经趋于平缓,但目标仍在继续。

所以还有很多事情要做。

泰森: 你在性能方面投入了大量的研究和思考。Solid反映了这一点(正如在基准中所看到的),但Solid也给我留下了非常干净的开发体验。这是Solid团队的一个重点,还是说这更像是一个快乐的副作用?

Carniato: 嗯,我开始使用Knockout是因为我喜欢DX[开发者体验]。我喜欢这种控制。但同时我也看到了React的早期媒体所强调的所有缺陷。所以我看了看我们如何能修复它。既然公式已经存在了,我就没有再走弯路了。我更专注于证明性能。但使Knockout强大的特性,如可组合的基元和声明性数据模式,继续对DX产生积极影响。

我没有发明新的抽象概念,而是不断发现我已经有了这些工具。这在某种意义上使事情变得更简单。所以我想两者都是?我从DX开始,想在性能上着陆,并在DX上巩固。

泰森: 我觉得该框架采用了一些反应式基元,并在其之上进行了分层,这使得它在精神上易于工作。Solid还提供SSR(服务器端渲染)。这仍然是一个需要扩展的领域。我知道这是个技术上的挑战。同构支持从一开始就是你们愿景的一部分吗?你在做这件事时有什么经验?

Carniato:哈...完全不是。我非常重视客户端的渲染比服务器的渲染快。公平地说,我当时的做法是这样的。当外面的框架等待异步数据响应时(就像你在Next、Nuxt或Sapper中发现的那样),客户端渲染甚至可以在绘画和TTI(交互时间)方面击败它。我在发布像Realworld Demo这样的东西时,很满意Solid的得分比这些服务器渲染的实现更好。但这只是在快速网络上才是真的。

随着时间的推移,人们会看到Solid的性能,而SSR成为最需要的功能,甚至不需要。我只做过交互式的,在登录应用程序后面的工作,所以我在这里没有经验。幸运的是,我遇到了Marko,eBay的框架,它已经基本完善了SSR的艺术。Solid和Marko的目标略有不同,但这两个项目都从对方那里得到了巨大的好处。

为了Solid的利益,我接触到了做SSR的最佳技术。这需要重新引导我的思维。但我接受了它,找出了如何编译成最理想的原始渲染,以及纳入流式SSR。后者并不难,因为我已经有了Suspense,所以我只是在服务器上允许它。正是在那个时候,我开始明白React这些年来一直在做什么(以及明年的React 18会有什么)。但我在去年夏天得以将其纳入Solid。而且这很令人惊讶。这就是未来。

泰森: 我需要研究一下Marko。

Carniato: 是的,人们不知道Marko,但是当它涉及到多页面应用程序和服务器渲染时,它已经在eBay生产水平上部署了十年之久的技术。其他框架刚刚开始增加他们已经拥有多年的功能。比如流式SSR和部分水化。

泰森: 你能描述一下水合的工作原理,以及为什么部分水合是一种改进?

Carniato: 这是在浏览器中首次在客户端运行组件的过程,以便为未来的更新做好准备。我们不渲染任何东西,但它通常遵循相同的自上而下的执行方式。因此,部分水化是关于不运送所有的组件代码。向浏览器发送较少的JavaScript可以提高页面加载和交互速度。

不幸的是,你只能在某些类型的应用程序中真正利用部分水合作用。我们典型的单页应用程序并不能真正利用这一点,因为最终所有的东西都需要在浏览器中。这相当于懒惰的加载。但在多页面应用程序中,真正的部分水合意味着永远不会发送JavaScript。

部分水合可能有点偏离主题,因为它需要一个不同的应用架构来利用,而且现在几乎没有框架为这种情况进行优化。我们刚刚开始看到像Astro这样的东西在这方面的尝试。

Tyson: 谢谢你的描述。你能不能简单地描述一下流式SSR?

Carniato:好的,你问的都是些棘手的问题!

流式SSR是围绕着我们可以边获取边渲染的想法。如果你曾经在浏览器中开发过一个异步加载的页面,你往往会开始渲染你的组件,并开始获取数据,显示一个占位符。当数据加载后,你再渲染内容。所有流式SSR都是在服务器上做同样的事情。

当你请求你的页面时,它开始渲染和获取异步数据。它立即开始用所有的占位符将响应流传回来,所以客户端不需要等待。然而,它保持响应流的开放。所以当数据加载完成后,它可以被渲染并沿着流发送。我们用它冲出脚本标签,通知浏览器应用程序是时候插入新的部分,并在它们进来的时候给它们注入水分。

因此,最终的结果是立即发送页面的同步部分,而不需要等待带有占位符的async,这与客户端的加载体验非常相似。你看到的是可用的内容加载,但这比客户端渲染更快,因为你能够从最初的服务器请求开始处理,而不是等待页面被发送到浏览器以及JavaScript被请求和处理。但最重要的是,你可以像以前一样写你的应用程序。我们不需要把获取数据的工作抬出来。它只是拥有与客户端相同的心理模型。

这是一个世界上最好的方案。很明显,我们可以看到为什么React对在React 18中引入这个功能感到兴奋。

**泰森。**哇,谢谢你对这个问题的深入研究。我接下来要问的是Suspense。React为了让Suspense工作,不得不对一些事情进行深入研究,对一个新的渲染引擎进行了突破性的改变。你们觉得这是个很难实现的事情吗?

Carniato: 是的,哈...我经历了几个不同的版本。我认为人们没有意识到,当一个像Vue或Preact这样的框架说它有Suspense时,是多么的不对等。在屏幕外渲染占位符和新内容是相对容易的。是 "过渡 "和并发渲染使其更具挑战性。这些框架并不支持这些。

我的第一个模型真的很简单,只是围绕着每个嵌套控制流的现实分支。但这需要人们在每个控制流中选择加入,这是很尴尬的。

我的第二种(也是目前的)方法是指当每个反应性原子被一个过渡所表示时,收集并分叉。然后所有未来的变化要么被应用于过渡分支(如果它们本身是一个过渡),要么被应用于两者(如果它们是定期更新)。

这意味着,当我分叉现实时,只有一个未来被并发地处理。我想不出如何像React提到的那样破解多个未来,我想这已经很好了,所以我就在一年前发布了它,并以此为基础。结果,React刚刚宣布他们也为React 18采用了单一的未来,所以看来我不是一个人发现多个未来的现实真的很难有效地调和。

幸运的是,当时Solid还是0.x版本,并没有太多的破坏性变化。请记住,Solid组件只渲染一次,而且大多数通信都是通过反应式系统颗粒化进行的。除非开发者把他们从多个分支中读到的非反应式值吊出来,否则其余的都是由Solid控制通信的事实来处理的。

泰森: 明白了。我觉得我们已经从编码变成了科幻小说中的现实分叉。我对这个答案只有一个后续问题和最后一个问题--非常感谢你的时间。

在React中,Suspense依赖于一个数据存储,它实现了与Suspense组件互动的API。Solid是否通过createResource 函数做类似的事情?(我还没有进入Solid的getResource )。)

Carniato: 是的。区别在于它是反应式的,而不是重新渲染。它与其说是一个缓存,不如说是一个特殊的信号,它知道它的数据什么时候是陈旧的,所以在以后的某个时间点,当它被读取时,我们可以确保通知它上面的任何悬念上下文,它需要做一些事情。(是的,Solid的Suspense是用Context API实现的。)但这个特殊的基元是一个福音,因为它也更像服务器上的一个缓存,因为它有利于SSR的客户端和服务器之间的数据自动序列化。它还能帮助我们注册承诺,以便服务器渲染知道它什么时候完成,并能关闭流。

泰森:很好。所以,您在Solid中投入了大量的工作(自2018年以来在GitHub项目上提交了约800次)。是什么让你有了动力?

Ryan Carniato:这是件有趣的事。我不知道这是什么时候改变的。就像我有一天决定,我在工作中没有做足够的开发工作,因为我进入了更多的管理职位,而且当时我和我刚出生的女儿熬夜。于是我开始修补,并在那个时候开始更多地拿起它。但我还是把它作为我自己的一个新奇的东西,放在一个私人 repo上。然后我发现了JS框架的基准,并意识到[我所采取的]方法可能是快速的,所以我开放了[我的项目]的源代码,这样我就可以被包括在内。

有一段时间,这就是激励我的动力--只是为了缩短时间,找出如何成为最快的。然后React发布了Hooks,一切都改变了。说实话,我简直不敢相信。就像他们刚刚给Solid指出了方向。我开始写文章,在很长一段时间里,只是知道我们在做一些事情,一直在推动着我前进。对于我们还没有发布的东西,我仍然有这种感觉。

每一个新问题似乎都会从一个弱点变成一个优势。当事情看起来进展顺利时,这是一种不可思议的感觉。我只是无法想象事情会以其他方式发展。我被迷住了(原谅我的双关语)。

泰森: 是的,世界似乎一直在转变,以证明Solid公司所做的不同设计选择是正确的,这很不寻常。我知道我学到了一些东西。你有什么想补充的吗?

卡尼亚托: 可能只有这个。有很多关于这个框架和那个框架的喋喋不休和叙述,这都是夸张的。可以肯定的是,框架和库的选择是有影响的。但是,你总是会达到这样的结果:你正在用你所拥有的工具来构建一个产品,而这个解决方案有点混乱,也许不是最优雅的。但是有一个现实,你有一个最后期限要满足。

尽管我们喜欢做理论上的军备竞赛,并说事情 "严格来说 "是更好的,但它只涉及到开发人员使用这些工具的能力。

如果说我们在Solid上取得的成就有什么启示的话,那就是仍有探索的空间,既定的界限和惯例仍有扩展的空间。专注地工作,但当你在另一边评估事情时,不要成为那个只把所有东西都放在一个盒子里然后继续前进的人。如果有这种心态,Solid就不会在这里,下一个大事件也不会在这里。