Vue中.vue文件比main.js先執行的問題及解決

問題

在main.js,App.vue和兩個子組件(A.vue和B.vue)中分別輸出語句,查看他們的加載順序:

main.js

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

new Vue({
        el: '#app',
        render: h => h(App),
        beforeCreate() {
            Vue.prototype.$bus = this //安裝全局事件總線
        },
    })
console.log('mainjs===============')

App.vue

<template>
    <div >
        <A/>
        <B/>
    </div>
</template>

<script>
    import A from './components/A'
    import B from './components/B'

    export default {
        name:'App',
        components:{A,B},
        mounted(){
            console.log('APP==================')
        }
    }
</script>

A.vue

<template>
    <div >
    </div>
</template>

<script>
    export default {
        name:'A',        
        mounted() {
            console.log('A=============')
        }
    }
</script>

B.vue

<template>
    <div >
    </div>
</template>

<script>
    export default {
        name:'B',
        mounted() {
            console.log('B==================')
        },
    }
</script>

執行結果:

在這裡插入圖片描述

可以看到main.js理論上應該是最先執行的,但是結果卻正好相反。

解釋

Vue加載時的執行順序如下

1、執行index.html文件

2、執行main.js文件

3、main.js掛載瞭app.vue文件,用app.vue的templete替換index.html中的<div id="app"></div>

4、main.js中註入瞭路由文件,將對應的組件渲染到router-view中

5、router-view中加載Layout文件

6、Layout 加載Navbar, Sidebar, AppMain

main.js確實是最先執行的,但是出現上述問題的原因是ES6的模塊化加載規則。

ES6模塊化加載規則

ES6 模塊化的設計思想是盡量的靜態化,使得編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。

而CommonJS 和 AMD 模塊化,都隻能在運行時確定這些東西。比如,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

// CommonJS模塊
let { stat, exists, readfile } = require('fs');

// 等同於
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上面代碼的實質是整體加載fs模塊(即加載fs的所有方法),生成一個對象(_fs),然後再從這個對象上面讀取 3 個方法。

這種加載稱為“運行時加載”,因為隻有運行時才能得到這個對象。

ES6 模塊化不是引入一個對象,而是通過export命令顯式指定輸出的代碼,再通過import命令輸入。

// ES6模塊
import { stat, exists, readFile } from 'fs';

上面代碼的實質是從fs模塊加載 3 個方法,其他方法不加載。

我的理解是,ES6的模塊化規則類似於cpp中的宏,在代碼編譯時進行字符串替換,上述代碼使用import語句引入瞭 stat, exists, readFile 三個方法,那麼在編譯時,三個方法名其實已經被替換成瞭方法代碼本身,存在於當前模塊當中,我們自然就可以使用引入的這些方法。

官方將這種加載稱為“編譯時加載”或者靜態加載,即 ES6 可以在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。

原因

因為是編譯時加載,自然而然就存在編譯優化。

import命令具有提升效果,會提升到整個模塊的頭部,首先執行。

這也很好理解,我們引入瞭模塊,並使用模塊中的成員,那麼當然要先引入才能使用。

下面的代碼不會報錯,因為import的執行早於foo的調用。這種行為的本質是,import命令是編譯階段執行的,在代碼運行之前。

foo();

import { foo } from 'my_module';

在main.js文件中,就算我們將import語句放到代碼最後,輸出結果也不會變,仍然是A->B->App>main.js。

Vue.config.productionTip = false

new Vue({
        el: '#app',
        render: h => h(App),
        beforeCreate() {
            Vue.prototype.$bus = this //安裝全局事件總線
        },
    })
console.log('mainjs===============')
import Vue from 'vue'
import App from './App.vue'

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: