BetaSu / fe-hunter

每天一道题,3个月后,你就是面试小能手,答题还能赚钱哦
1.67k stars 116 forks source link

运行时/编译时前端框架都有哪些优缺点? #62

Open BetaSu opened 2 years ago

BetaSu commented 2 years ago

发生问题的场景

主流的前端框架从实现原理讲,一般分为:

你能从以下角度回答该问题么?

需要解决的问题

  1. 列举对应的框架,分别解释什么是运行时、编译时、运行时 + 编译时?
  2. 它们有哪些优缺点?

最佳答案评选标准

  1. 答案遵循以上顺序作答

最佳答案

悬赏中,欢迎作答...

答题同学须知

围观同学须知

a145789 commented 2 years ago

运行时

纯运行时框架比较好理解,举一个例子 JQuery .虽然 JQuery 并不能称之为框架,但我们可以看到 JQuery 的一些特点,不需要在 html 上做一些例如 v-show v-bind 的标记,也不需要稀奇古怪的写法,也不需要什么特定的环境,引入一个 script 文件即可,只是一个单纯的 js库 ,优化了 jsDom 之间的交互。同样的,在 React 身上我们也可看到许多共通点,React 在 js 层面上也没有许多稀奇古怪的写法,以 一切皆在 js 之下 为基准,也许这也是 React 自称一个 视图库,而不把自己当成一个框架的原因。当然这一切都在不考虑 Jsx 的情况下,React 的运行时体现在与视图的交互比如 虚拟 dom fiber 等。不使用 Jsx 手写 render 函数 虽然效果一样,但是尤为的繁琐,所以是在前端工程化的今天出现了编译。既然项目最后需要经过层层转译 tree-shake UglifyJS.minify 打包生成,那我为什么不加一层转译让开发者的体验更好,Reactrender 函数 变为 Jsx语法糖 的形式出现,让诸多开发者的开发体验极大提升,React 还是一个纯运行时的库,Jsx 语法本质上依然还是 render 函数 ,你写怎样的 Jsx 就会编译为怎样的 render 函数,同样的只要你想,你也可以无压力把 render 函数 反编译为 Jsx 这二者只不过在开发阶段展现给你的形式不一样,这样就可以引申出下一个 编译-运行时 框架 Vue

编译-运行时

为什么称 Vue 为 编译-运行时 框架?因为 Vue 既可以当作一个纯运行时的视图库,同时又与编译分隔不开。如果你可以像使用 React 一样使用 Vue,你会发现 Vue 就是自动挡版本的 React ,你需要 setState 我只需要 state.value = ‘’ 直接触发视图更新,Vue 也使用了 render 函数,甚至你可以在 Vue 中使用 Jsx ,此时 Vue 可以保证 一切皆在 js 之下 ,你把 Vue 当作一个单纯的 MVVM 的视图库就可以。那 Vue 的不可分隔的编译体现在哪?就是我们所熟知的 template ,为什么因为模板 Vue 被归类为 编译-运行时 框架,而 React 也有 Jsx 却仍然是 纯运行时框架。我们可以看两段代码。

// template
<div>
    <h1 v-if="true" />
    <h2 v-else />
</div>
// 编译后的render 函数 伪代码
// h('div', { children: true ? h('h1') : h('h2') })

<div>
    { true ? <h1 /> : <h2 /> }
</div>

// h('div', { children: true ? h('h1') : h('h2') })

可以看到其实二者的 render 函数其实可以保持一致,但是 jsx 只是将转换 Html 元素为 render 函数,而模板则将 if else 逻辑一同转换出来,再举一个例子

<div>{s ?? <h1 />}</div>

jsx 可以很轻松的转换为 h('div', { children: s ?? h('h1') }),如果在 vue 模板中就无法这样写,只能

<div>
  <h1 v-if="s != null" />
</div>

// 转换出来的代码为 h('div', { children: s != null && h('h1') })

可以看到在使用模板的时候有许多限制,这也是为什么很多 React 开发者会说写 jsx 就像在写 js ,因为写 jsx 就是在写 js。看到这里好似模板编译一无是处?那接下来就是编译发力的阶段。

既然我使用编译了,那就贯彻到底。虽然模板在 js 层面有很多限制,但是也得到了更多的能力,比如 Vue3 带来的性能改进,静态内容提升。还是上面的例子,对于 render 函数而言,jsx 只能原封不动的编译

<div>{true ? <h1 /> : <h2 />}</div>

//   h('div', { children: true ? h('h1') : h('h2') })

这样想要重新生成虚拟 Dom 就需要层层调用 h 函数,但是模板可以可以做一些性能优化

;<div>
  <h1 v-if="true" />
  <h2 v-else />
</div>

const h1 = h('h1')
const h2 = h('h2')

//   h('div', { children: true ? h1 : h2 })

这样再次生成 虚拟 Dom 的时候就节省两个函数执行的开销,还可以体现编译好处的就是 Vue 的指令,比如 v-show 这个指令,你可以想想在 React 中想要实现这个功能绝对没有直接写个 v-show 方便。此外你可以自定义指令,假设有个需求需要将权限控制细分到按钮,在 Vue 中你可以写一个 v-permission 指令,只需要加到 <button v-permission> 就可以,如果在 React 中可就要废一番脑细胞了。

Vue 使用编译的好处不仅体现在模板中,我们都知道 Vue 使用了单文件 .vue 的形式,这样也可以对 scriptcss 做优化,例如想要实现 css 隔离,只需要加一个简单的 scoped 就可以了,而 React 催生一大堆 css 方案,生态丰富是好事,但有时候想解决痛点只有一个就好了。在 Vue3 引入了 Composition Api ,Composition Api 在 js 下总有许多不舒服的地方,比如繁杂的 return 返回,ref 一个变量需要写繁琐的 .value,而这些 Vue 也正在通过编译的方式解决 script-setup

纯编译

对于纯编译框架 Svelte 了解的不多,只知道不需要虚拟 dom,通过编译对每个 Html 元素添加增删改方法,可以极细粒度的控制元素变更,轻运行时,性能很好。

总结

,主要对比了 ReactVue 之间有关 运行时-编译时 之间的不同。其实你会发现虽然 Jsx 只是算做 React 生态的一部分,但也绕不开编译,只不过这个编译对 Js 能力几乎无影响。Vue 不使用模板也可以当作纯运行时的一个框架,但使用模板编译去拓展了很多能力。使用编译的初衷都是缘因对 Html-Js-Css 的不爽。render 函数 很烦,那我就创造一个 Jsx,需要返回一大堆无用的东西,那我就开发 script-setup

利弊

二者之间的利弊其实挺明显的,纯运行时框架最大的利就是不会与 Js 有差异化,Js 能用的我都能用,尤其体现在生态方面,比如接入 Typescript 基本不需要什么 hack 方式。弊也很明显,能力只能局限在 Js 中,当性能出现瓶颈的时候,只能通过 Js 运行时的方式去解决,比如 fiber 并发模式。其实 Jsx 真的无法做编译时优化么?肯定是可以的,但是做了,也就不是一个纯粹的视图库了。

编译的利就是拓展了很多能力,觉得 Web 语法不爽,甚至可以搞一套自己喜欢的语法,只要最后编译为 Html-Js-Css 就可以了,但是弊就是要自己抹平与 Js 之间的差异,Vuetemplate 模板对 Typescript 支持也是老生常谈的问题,比如出现的新语法 ?? ?. 这些想要在模板中使用都需要框架开发者主动去支持,如果没有人力及时支持怎么办?只能放弃使用或者自己发挥主观能动性。

Garker commented 2 years ago

Svelte这种纯编译的框架,因为在运行前直接编译生成HTML代码而不是像react和vue这样生成vdom转换为HTML,因为少了在运行时候的转换所以减少了一些性能上的开销,但直接编译为HTML也给Svelte这种纯编译的框架带来了最大的弊端,不灵活只能局限在浏览器以及支持HTML格式的软件中使用reactvue生成的是vdom,大家都知道vdom就是描述元素状态的对象(例如:一个div的大小尺寸等),而vdom在不同环境中表现的形式不一样,正因为vdom的存在使得reactvue可以生成桌面端,移动端(react native)的应用。

简单总结:纯编译框架在做到性能优化的同时失去了灵活性,react就是纯粹的运行时框架,vue则是中庸之道在各个框架吸取精华

前端小白 用过的框架也只有react 所以说的很片面 肯定也有错的地方,欢迎指正