天天看點

Vue3為什麼這麼快?

Vue3為什麼這麼快?

總所周知,程式員追求的就是一個字:快!(當然不是什麼都追求快的,有些事情快起來是不行滴)

昨天Vue3.0正式釋出了,激動的心,顫抖的手,摸了摸我的頭發,嗯~還好。

據說Vue3.0相比Vue2.x在性能上提升了1.2~2倍,為啥他就這麼快呢?vue3.0做了以下事情

  1. diff算法優化
  2. 靜态提升(hoistStatic)
  3. 事件偵聽器緩存(cacheHandlers)
  4. SSR優化(看心情更新)

Vue2.x的diff算法

vue2.x的diff算法叫做全量比較,顧名思義,就是當資料改變的時候,會從頭到尾的進行vDom對比,即使有些内容是永恒固定不變的。

Vue3為什麼這麼快?

Vue3.0的diff算法

vue3.0的diff算法有個叫靜态标記(PatchFlag)的小玩意,啥是靜态标記呢?

簡單點說,就是如果你的内容會變,我會給你一個flag,下次資料更新的時候我直接來對比你,我就不對比那些沒有标記的了

Vue3為什麼這麼快?
export function render(_ctx, _cache, $props, $setup, $data, $options) {  return (_openBlock(), _createBlock("div", null, [    _createVNode("p", null, "'HelloWorld'"),    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)                                               //上面這個1就是靜态标記  ]))}      

那麼肯定有人又會問了,為啥是個1呢?

TEXT = 1 // 動态文本節點CLASS=1<<1,1 // 2//動态classSTYLE=1<<2,// 4 //動态stylePROPS=1<<3,// 8 //動态屬性,但不包含類名和樣式FULLPR0PS=1<<4,// 16 //具有動态key屬性,當key改變時,需要進行完整的diff比較。HYDRATE_ EVENTS = 1 << 5,// 32 //帶有監聽事件的節點STABLE FRAGMENT = 1 << 6, // 64 //一個不會改變子節點順序的fragmentKEYED_ FRAGMENT = 1 << 7, // 128 //帶有key屬性的fragment 或部分子位元組有keyUNKEYED FRAGMENT = 1<< 8, // 256 //子節點沒有key 的fragmentNEED PATCH = 1 << 9, // 512 //一個節點隻會進行非props比較DYNAMIC_SLOTS = 1 << 10 // 1024 // 動态slotHOISTED = -1 // 靜态節點// 訓示在diff算法中退出優化模式BALL = -2      

Vue2.x中無論元素是否參與更新,每次都會重新建立然後渲染

Vue3.0中對不參與更新的元素,會做靜态提升,隻會被建立一次,在渲染時直接複用即可 還是這段熟悉的代碼,開啟靜态提升前

export function render(_ctx, _cache, $props, $setup, $data, $options) {  return (_openBlock(), _createBlock("div", null, [    _createVNode("p", null, "'HelloWorld'"),    _createVNode("p", null, "'HelloWorld'"),    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)  ]))}      

開啟靜态提升後編譯結果

const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "'HelloWorld'", -1 /* HOISTED */)              const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "'HelloWorld'", -1 /* HOISTED */)                  export function render(_ctx, _cache, $props, $setup, $data, $options) {               return (_openBlock(), _createBlock("div", null, [                 _hoisted_1,                 _hoisted_2,                 _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)               ]))              }           

可以看到開啟了靜态提升後,直接将那兩個内容為helloworld的p标簽聲明在外面了,直接就拿來用了,這麼搞的話那肯定會快啊

事件偵聽器緩存

預設情況下onClick會被視為動态綁定,是以每次都會去追蹤它的變化

但是因為是同一個函數,是以沒有追蹤變化,直接緩存起來複用即可

dom結構

<div>  <button @click = 'onClick'>點我</button></div>      

開啟事件偵聽器緩存之前:

export const render = /*#__PURE__*/_withId(function render(_ctx, _cache, $props, $setup, $data, $options) {               return (_openBlock(), _createBlock("div", null, [                 _createVNode("button", { onClick: _ctx.onClick }, "點我", 8 /* PROPS */, ["onClick"])                                                          // PROPS=1<<3,// 8 //動态屬性,但不包含類名和樣式               ]))              })           

這裡有一個8,表示着這個節點有了靜态标記,有靜态标記就會進行diff算法對比差異,是以會浪費時間

開啟事件偵聽器緩存之後:

export function render(_ctx, _cache, $props, $setup, $data, $options) {  return (_openBlock(), _createBlock("div", null, [    _createVNode("button", {      onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick(...args)))    }, "點我")  ]))}      
下一篇: Sprint3