<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3.0七大亮點(diǎn)

          共 6165字,需瀏覽 13分鐘

           ·

          2021-06-11 12:44

          點(diǎn)擊上方 前端瓶子君,關(guān)注公眾號

          回復(fù)算法,加入前端編程面試算法每日一題群

          來源:獵戶座小陳

          https://juejin.cn/post/6967570296677236743

          一,性能比2.x快1.2~2倍

          diff算法的優(yōu)化

          在vue2中,虛擬dom是全量比較的。

          在vue3中,增加了靜態(tài)標(biāo)記PatchFlag。在創(chuàng)建vnode的時(shí)候,會根據(jù)vnode的內(nèi)容是否可以變化,為其添加靜態(tài)標(biāo)記PatchFlag。diff的時(shí)候,只會比較有PatchFlag的節(jié)點(diǎn)。PatchFlag是有類型的,比如一個(gè)可變化文本節(jié)點(diǎn),會將其添加PatchFlag枚舉值為TEXT的靜態(tài)標(biāo)記。這樣在diff的時(shí)候,只需比對文本內(nèi)容。需要比對的內(nèi)容更少了。PatchFlag還有動態(tài)class、動態(tài)style、動態(tài)屬性、動態(tài)key屬性等枚舉值。

          render階段的靜態(tài)提升(render階段指生成虛擬dom樹的階段)

          在vue2中,一旦檢查到數(shù)據(jù)變化,就會re-render組件,所有的vnode都會重新創(chuàng)建一遍,形成新的vdom樹。

          在vue3中,對于不參與更新的vnode,會做靜態(tài)提升,只會被創(chuàng)建一次,在re-render時(shí)直接復(fù)用。

          靜態(tài)提升可以理解為第一次render不參與更新的vnode節(jié)點(diǎn)的時(shí)候,保存它們的引用。re-render新vdom樹時(shí),直接拿它們的引用過來即可,無需重新創(chuàng)建。

          事件偵聽緩存

          在vue2中,我們寫的@click="onClick"也是被當(dāng)作動態(tài)屬性,diff的時(shí)候也要對比。但我們知道它不會變化,比如變成@click="onClick2",綁定別的值。

          在vue3中,如果事件是不會變化的,會將onClick緩存起來(跟靜態(tài)提升達(dá)到的效果類似),該節(jié)點(diǎn)也不會被標(biāo)記上PatchFlag(也就是無需更新的節(jié)點(diǎn))。這樣在render和diff兩個(gè)階段,事件偵聽屬性都節(jié)約了不必要的性能消耗。

          我曾經(jīng)維護(hù)過一個(gè)擁有很龐大dom樹的頁面。由于節(jié)點(diǎn)非常多,無需參與更新的節(jié)點(diǎn)也很多,使用vue2的情況下,在render和diff兩個(gè)階段,消費(fèi)了很多性能,如果當(dāng)時(shí)有vue3的話,我想性能會被優(yōu)化很多。

          減少創(chuàng)建組件實(shí)例的開銷

          vue2.x每創(chuàng)建一個(gè)實(shí)例,在this上要暴露data、props、computed這些,都是靠Object.defineProperty去定義的。這部分操作還是挺費(fèi)時(shí)的。

          vue3.0中基于Proxy,減少了創(chuàng)建組件實(shí)例的性能開銷。

          二,按需編譯,體積比Vue2.x更?。═ree shaking)

          在vue3中,可以如下面這樣引用vue的功能函數(shù),如果你的項(xiàng)目沒有用到watch,那編譯時(shí)就會把tree shaking掉。

          import { computed, watch, nextTick } from "vue";
          復(fù)制代碼

          利用的就是 ES6 模塊系統(tǒng)import/export。

          三,Compostion API: 組合API/注入API

          這里要說到代碼的組織方式,傳統(tǒng)的網(wǎng)頁是html/css/javascript(結(jié)構(gòu)/樣式/邏輯)分離。vue/react通過組件化的方式,將聯(lián)系緊密的結(jié)構(gòu)/樣式/邏輯放在一起,有利于代碼的維護(hù)。

          compostion api更進(jìn)一步,著力于JavaScript(邏輯)部分,將邏輯相關(guān)的代碼放在一起,近而有利于代碼的維護(hù)。

          在vue2的組件內(nèi),使用的是Option API風(fēng)格(data/methods/mounted)來組織的代碼,這樣會讓邏輯分散,舉個(gè)例子就是我們完成一個(gè)計(jì)數(shù)器功能,要在data里聲明變量,在methods定義響應(yīng)函數(shù),在mounted里初始化變量,如果在一個(gè)功能比較多、代碼量比較大的組件里,你要維護(hù)這樣一個(gè)功能,就需要在data/methods/mounted反復(fù)的切換到對應(yīng)位置,然后進(jìn)行代碼的更改。

          在vue3中,使用setup函數(shù)。如下所示跟count相關(guān)的邏輯,都放到counter.js文件里,跟todo相關(guān)的邏輯放到todos.js里。

          import useCounter from './counter'
          import useTodo from './todos'

          setup(){
            let { val, todos, addTodo } = useTodo()
            let {count,add} = useCounter() 
            return {
              val, todos, addTodo,
              count,add,
            }
          }
          復(fù)制代碼

          在我看來這就是Compostion API最大的特點(diǎn),以功能為單位的代碼組織方式。同時(shí)它可以讓代碼更易重用。

          說到重用,Compostion API的方式也比mixin的方式好很多,你可以清楚的看到組件使用的數(shù)據(jù)和方法來自哪個(gè)模塊,而mixin進(jìn)組件的功能,常常會讓我們困惑此功能來自哪個(gè)mixin。

          四,更好的TS支持

          vue2不適合使用ts,原因在于vue2的Option API風(fēng)格。options是個(gè)簡單對象,而ts是一種類型系統(tǒng)、面向?qū)ο蟮恼Z法。兩者有點(diǎn)不匹配。

          在vue2結(jié)合ts的具體實(shí)踐中,要用 vue-class-component 強(qiáng)化 vue 組件,讓 Script 支持 TypeScript 裝飾器,用 vue-property-decorator 來增加更多結(jié)合 Vue 特性的裝飾器,最終搞的ts的組件寫法和js的組件寫法差別挺大。

          在vue3中,量身打造了defineComponent函數(shù),使組件在ts下,更好的利用參數(shù)類型推斷 。Composition API 代碼風(fēng)格中,比較有代表性的api就是 ref 和 reactive,也很好的支持了類型聲明。

          import { defineComponent, ref } from 'vue'
           
          const Component = defineComponent({
              props: {
                  success: { type: String },
                  student: {
                    type: Object as PropType<Student>,
                    required: true
                 }
              },
              setup() {
                const year = ref(2020)
                const month = ref<string | number>('9')
               
                month.value = 9 // OK
               const result = year.value.split('') // => Property 'split' does not exist on type 'number'
           }
          復(fù)制代碼

          五,自定義渲染API(Custom Renderer API)

          vue2.x架構(gòu)問題

          vue2.x最開始支持運(yùn)行在瀏覽器中,渲染到瀏覽器的dom上,隨著vue的流行,出現(xiàn)了weex和myvue。

          • weex:移動端跨平臺方案,需要渲染到移動設(shè)備。weex被寫在vue原項(xiàng)目里,缺點(diǎn)是這使vue原項(xiàng)目更大了,也不是通用解決方案。
          • myvue:小程序上使用,需要渲染到小程序框架上。myvue是單獨(dú)fork一份源代碼進(jìn)行更改,缺點(diǎn)也非常明顯,myvue中vue的版本跟官方版本從fork的那一刻開始,就要開始不一致了。

          vue2.x項(xiàng)目架構(gòu)對于這種渲染到不同平臺不太友好,vue3.0推出了自定義渲染API解決了該問題。

          下面我們先看vue2和vue3的入口寫法有所不同:

          // vue2
          import Vue from 'vue'
          import App from './App.vue'
          new Vue({ => h(App)}).$mount('#app')

          // vue3
          const { createApp }  from 'vue'
          import App from "./src/App"
          createApp(App).mount(('#app')
          復(fù)制代碼

          vue官方實(shí)現(xiàn)的 createApp 會給我們的 template 映射生成 html 代碼,但是要是你不想渲染生成到 html ,而是要渲染生成到 canvas 之類的不是html的代碼的時(shí)候,那就需要用到 Custom Renderer API 來定義自己的 render 渲染生成函數(shù)了。

          // 你自己實(shí)現(xiàn)一個(gè)createApp,比如是渲染到canvas的。
          import { createApp } from "./runtime-render";
          import App from "./src/App"; // 根組件

          createApp(App).mount('#app');
          復(fù)制代碼

          有了Custom Renderer API,如weex和myvue這類方案的問題就得到了完美解決。只需重寫createApp即可。

          六,更先進(jìn)的組件

          Fragment組件

          // vue2是不允許這樣寫的,組件必須有一個(gè)跟節(jié)點(diǎn),現(xiàn)在可以這樣寫,vue將為我們創(chuàng)建一個(gè)虛擬的Fragment節(jié)點(diǎn)。

          <template>
            <div>Hello</div>
            <div>World</div>
          </template>
          復(fù)制代碼

          這樣寫有何好處呢?一是如果根節(jié)點(diǎn)不是必要的,無需創(chuàng)建了,減少了節(jié)點(diǎn)數(shù)。二是Fragment節(jié)點(diǎn)是虛擬的,不會DOM樹中呈現(xiàn)。

          Suspense組件

          <Suspense>
            <template >
              <Suspended-component />
            </template>
            <template #fallback>
              Loading...
            </template>
          </Suspense>
          復(fù)制代碼

          在Suspended-component完全渲染之前,備用內(nèi)容會被顯示出來。如果是異步組件,Suspense可以等待組件被下載,或者在設(shè)置函數(shù)中執(zhí)行一些異步操作。

          七,更快的開發(fā)體驗(yàn)(vite開發(fā)構(gòu)建工具)

          在使用webpack作為開發(fā)構(gòu)建工具時(shí),npm run dev都要等一會,項(xiàng)目越大等的時(shí)間越長。熱重載頁有幾秒的延遲,但是如果用vite來做vue3的開發(fā)構(gòu)建工具,npm run dev 秒開,熱重載也很快。這種開發(fā)體驗(yàn)真是很爽,拒絕等待。

          vite的原理還是用了瀏覽器支持import關(guān)鍵字了,啟動項(xiàng)目不用webpack構(gòu)建工具先構(gòu)建了,瀏覽器直接請求路由對應(yīng)的代碼文件,代理服務(wù)器針對單個(gè)文件進(jìn)行編譯并返回。如果請求的文件里還import了其他文件,同理瀏覽器繼續(xù)發(fā)請求,代理服務(wù)器返回。就這樣實(shí)現(xiàn)了npm run dev時(shí)無需編譯,實(shí)時(shí)請求實(shí)時(shí)編譯。

          總結(jié):

          其他的,數(shù)據(jù)監(jiān)聽方式變成了Proxy,消除了Object.defineProperty現(xiàn)有的限制(例如無法檢測新的屬性添加),并提供更好的性能。

          vue3解決了vue2的一些問題,大型應(yīng)用的性能問題、ts支持不友好問題,自定義渲染API解決體系架構(gòu)存在的問題,如果在vue3的基礎(chǔ)上實(shí)現(xiàn)weex框架會好很多。也做出了很多優(yōu)化,Compostion API讓代碼的組織形式更好。vite開發(fā)構(gòu)建工具讓開發(fā)體驗(yàn)更好,Tree shaking讓包更小、性能更優(yōu)。

          總的來說vue3還是非常棒的,帶來了很多非常好的新特性。

          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會很認(rèn)真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
           》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持



          瀏覽 26
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国内色图 | 亚洲艹逼网站 | 黄色天天影视 | 强开小嫩苞一区二区三区视频 | 性视频午夜男女 |