1. 程式人生 > >Vue.js中的非同步元件

Vue.js中的非同步元件

隨著應用程式越來越大,你開始考慮優化應用程式,使其變得更快。在此過程中,你可能使用了拆分程式碼和延遲載入這兩種方法,它們通過將程式碼塊的加截推遲到需要的時候載入,從而使應用程式的初始包變得更小。

延遲載入對於應用程式路由有很大的意義,並且有很大的影響,因為每個路由都是應用程式的不同部分。

延遲載入有意義的另一種情況是元件延遲渲染。這些元件可以是tooltipspopovermodal等,當然這些元件也可以使用非同步元件

讓我們來看看如何在Vue中構建延遲載入非同步元件。

延遲載入元件

在我們開始瞭解延遲載入元件之前,我們先來了解通常是如何載入元件的。 為此,我建立了一個Tooltip.vue

元件:

<!-- Tooltip.vue -->
<template>
    <h1>Hi from Tooltip!</h2>
</template>

這裡沒有什麼特別之處,它就是一個簡單的元件。我們可以通過本地註冊,匯入Tooltip元件並將其新增到components選項中,這樣就可以在另一個元件中使用它。比如,在App.vue中使用它:

<!-- App.vue -->
<template>
    <div id="app">
        <Tooltip />
    </div>
</template>

<script>
    import Tooltip from "./components/Tooltip"

    export default {
        name: "App",
        components: {
            Tooltip
        }
    };
</script>

只要App被匯入,就可以在初始載入時,Tooltip元件就會被匯入、使用和載入。但是想想:只有在我們要使用元件時才載入該元件難道沒有意義嗎?使用者很可能在不需要工具提示的情況下瀏覽整個系統。

為什麼我們要在應用程式開始時花費寶貴的資源來載入元件呢?我們可以應用延遲載入和程式碼拆分來改進它。延遲載入是在稍後的階段載入某些內容的技術。

雖然程式碼拆分是將一段程式碼拆分到一個單獨的檔案(稱為chunk)中,以便減少應用程式的初始包,從而減輕初始載入。

通過使用動態匯入(Dynamic import),Vue可以輕鬆應用這些技術。在ES2018中也會具有這樣的功能,它允許程式在執行時載入模組。我閃將有一篇文章深入探討這些概念,但讓我們從實用和簡單的角度開始吧。

現代的繫結器(Modern bundlers),比如Webpack(從版本2開始),RollupParcel將理解這種語法並自動為該模組建立一個單獨的檔案,該檔案將在需要時載入。

我在這裡認為你已經熟悉了靜態方式匯入模組。然而,動態匯入是一個返回Promise的函式,其中包含模組作為其有效的載入。下面的示例展示瞭如何以靜態匯入和動態方式匯入utils模組。

// 靜態匯入模組
import utils from './utils'

// 動態匯入
import('./utils').then(utils => {
    // 可以在這裡使用utils模組
})

在Vue中延遲載入元件與在封裝的函式中動態匯入元件一樣容易。在前面的例子中,我們可以像下面這樣延遲載入Tooltip元件:

export default {
    components: {
        Tooltip: () => import('./components/Tooltip')
    }
}

使用() => import('./components/Tooltip')替代前面示例中的import Tooltip from "./components/Tooltip"。Vue一旦請求渲染將會延遲載入該元件。

不僅如此,它還將應用程式碼拆分。你可以使用上面提到的任何繫結器執行程式碼來進行測試。最簡單的方式就是使用vue-cil,但在文章的最後,你將找到一個已經構建好的Demo。執行後,開啟開發者工具,在Network一欄將可可以看到一個名為1.chunk.js這樣的JavaScript檔案。

有條件地載入一個非同步元件

在前面的示例中,儘管我們通過延遲載入來載入Tooltip元件,但它將在需要渲染時立即載入,這在App元件載入時就立即發生了。

然而,在實踐中,我們希望將Tooltip元件載入能延遲到需要時載入,這通常是在觸發某個事件之後有條件地進行,比如在按鈕或文字上懸停時觸發。

為了簡單起見,在App元件中新增一個按鈕,使用v-if有條件地渲染Tooltip元件:

<!-- App.vue -->
<template>
    <div>
        <button @click="show = true">Load Tooltip</button>
        <div v-if="show">
            <Tooltip />
        </div>
    </div>
</template>

<script>
    export default {
        data: () => ({
            show: false
        }),

        components: {
            Tooltip: () => import('./components/Tooltip')
        }
    }
</script>

請記住,Vue在需要渲染之前不會使用該元件。這意味著在點選之前不需要該元件,並且該元件將被延遲載入。

非同步元件的使用者體驗

大多數情況下,非同步元件載入速度非常快,因為它們是從主包中拆分出來的小塊程式碼。但是想象一下,你在一個非常慢的網路環境下緩慢的載入一個大的模態(Modal)元件。這可能需要一些時間來載入和渲染。

當然,你可以使用一些優化,比如HTTP快取或資源提示,以低優先順序預載入到記憶體中。事實上,新的vue-cli會對這些延遲載入的塊預先獲取。不過,在一些情況下,載入可能需要一些時間。

從使用者體驗的角度來看,如果一個任務需要超過1s的時間,你就會開始失去使用者的注意力。

但是,可以通過向用戶提供反饋來保持注意力。為了吸引使用者的注意力,我們可以在載入時使用progress(進度條)元件,但是在非同步載入時,我們如何使用一個漂亮的loadingprogress元件呢?

載入元件

你還記得我們使用一個帶有動態匯入的函式來延遲載入非同步元件嗎?

export default {
    components: {
        Tooltip: () => import('./components/Tooltip')
    }
}

通過返回物件而不是動態匯入的結果來定義非同步元件長期的方法。在該物件中,我們可以定個一個載入元件:

const Tooltip = () => ({
    component: import('./components/Tooltip'),
    loading: AwesomeSpinner
})

這樣,在預設延遲200ms之後,元件AwesomeSpinner就會顯示出來。你也可以自定義延遲時間:

const Tooltip = () => ({
    component: import('./components/Tooltip'),
    loading: AwesomeSpinner,
    delay: 500
})

作為載入元件應該使用的元件必須儘可能的小,以使它幾乎能立即載入

錯誤元件

同樣的,我們可以用延遲載入元件的方式來定義一個錯誤元件:

const Tooltip = () => ({
    component: import('./components/Tooltip'),
    loading: AwesomeSpinner,
    error: SadFaceComponent
})

載入./components/Tooltip元件出錯時,SadFaceComponent元件將會顯示。在下面這幾種情況之下可能會發生這種情況:

  • 網路癱瘓(連不上網)
  • 該元件不存在(這是一種嘗試它的好方法,你可以自己故意刪除它)
  • 載入超時

預設情況下,沒有超時,但我們可以自己配置:

const Tooltip = () => ({
    component: import('./components/Tooltip'),
    loading: AwesomeSpinner,
    error: SadFaceComponent,
    timeout: 5000
})

現在,如果在5000ms之後Tooltip元件還未載入,將會顯示SadFaceComponent元件。

總結

你已經瞭解瞭如何在自己的塊檔案中分割元件,以及如何使用動態匯入來延遲載入元件。我們還通過有條件地渲染資料來延遲資料塊的載入。

雖然非同步元件可以通過分割和延遲的載入方式來提高應用程式的載入時間,但它們可能會對使用者體驗有很大的影響,尤其是當它們很大的時候。控制載入狀態允許我們提供反饋,並在速度很慢的情況下讓使用者參與進來。