vue項目加載第3方js優化

項目寫到最後須要優化的時候,發現有不少首屏用不到的第3方js都寫在index.html裏,嚴重拖慢的網頁的加載速度,這裏的第3方組件大多不能經過npm或其餘模塊安裝,因此不能直接用vue裏的異步組件,好比高德地圖的jssdk和它的ui組件,最簡單的方法就是在document裏插入script。 因此就有了下面的方案。javascript

先定義一個把js插入到document裏的方法

# asyncLoadJs.js
export default function asyncLoadJs (url) {
  return Q.Promise((resolve, reject) => {
    let hasLoaded = $('script[src="'+url+'"]').length > 0
    if (hasLoaded) {
      resolve()
      return
    }

    let script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = url
    document.body.appendChild(script)
    script.onload = () => {
      resolve()
    }
    script.onerror = () => {
      reject()
    }
  })
}

在按第3方js依賴的不一樣 分紅各個函數

這裏以我項目裏的高德地圖組件爲例,它須要一個主jssdk庫和一個提供ui的庫,ui庫是依賴主庫的。html

# asyncLoadJs.js
export function loadAMapJS () {
  return Q.Promise((resolve, reject) => {
    asyncLoadJs('https://webapi.amap.com/maps?v=1.3&key=[你本身的key]&plugin=AMap.ToolBar,AMap.Geolocation,AMap.Autocomplete')
      .then(() => {
        return asyncLoadJs('https://webapi.amap.com/ui/1.0/main.js')
      })
      .then(() => {
        resolve()
      })
      .catch(err => {
        reject(err)
      })
  })
}

在組件生命週期中使用異步加載

# position-picker.vue
<script>
    import {loadAMapJS} from '../../libs/asyncLoadJs'
    
    let loadedAMapJS = false // 是否加載完js
    
    export default {
        created () {
          // 判斷是否加載過
          if (!loadedAMapJS) {
            loadAMapJS().then(() => {
              loadedAMapJS = true
            })
          }
        },
        mounted () {
          // 循環判斷有沒有加載完 寫在mounted生命週期裏是應爲高德的api依賴dom
          let interval = setInterval(() => {
            if (loadedAMapJS) {
              clearInterval(interval)
              this.init()
            }
          }, 300)
        },
        init () {
            let AMap = window.AMap
            let AMapUI = window.AMapUI
            AMapUI.loadUI(['misc/PositionPicker'], function (PositionPicker) {
              self.map = new AMap.Map(self.$refs['map'], {
                zoom: 16,
                scrollWheel: false
              })
              ...其餘代碼
            })
        }
    }
</script>

一個頁面有多個第3方組件的問題

若是一個頁面有多個第3方組件,那隻定義一個是否加載完的標誌位是不夠的,由於組件基本是同時created的,在dom中插入script標籤後都會返回resolve,其實這時js是沒有加載完的,這時能夠加一個是不是第一次請求js的變量。vue

# position-picker.vue
<script>
    import {loadAMapJS} from '../../libs/asyncLoadJs'
    
    let loadedAMapJS = false // 是否加載完js
    let firstLoadingAMapJS = true // 否是第一次請求
    
    export default {
        created () {
          // 判斷是否加載過
          if (!loadedAMapJS && firstLoadingAMapJS) {
            firstLoadingAMapJS = false // 立刻置爲false 只讓第一個created組件去請求js
            loadAMapJS().then(() => {
              loadedAMapJS = true
            }).catch(() => {
              firstLoadingAMapJS = true // 出錯置爲true 下次進來仍是能從新請求js
            })
          }
        }
        ...
    }
</script>

注意事項

在computed或watch中,若是須要用到第3方js方法的地方必須先判斷第3方js是否加載完,否則會報錯的~java

相關文章
相關標籤/搜索