Hey, 看看小程序的page-frame.html把~

嘿,各位做爲小程序的開發者,有認真看太小程序的page-frame.html嗎!想要告訴你們,頗有必要的喔!經過這段html,管中窺豹,能夠領悟到小程序代碼的加載流程,還蠻有收穫的,故在此記錄一番~html

在此以前,先強烈安利有贊團隊的從源碼看微信小程序啓動過程 ,超良心超有料,我看了三遍都麼有徹底領悟得道(¯∀¯٥)…有想深刻了解的同窗能夠研讀一下這篇文章~node

page-frame.html

其實我以爲從模塊引用和頁面展現來講,小程序開發頗像開發單頁應用。雖然開發小程序時會分不一樣的頁面來編寫,但實際呈現出來的是一張大頁面,也就是page-frame.html。webpack

在開發者工具的控制檯輸入document,便可以清晰獲得整段html。以下圖:es6

整份html的各個部分在這裏就再也不贅言啦,基本是初始化全局變量>>加載框架WAService.js>>加載業務代碼的過程。而我最感興趣的是業務代碼的加載。web

顯而易見,每一份js代碼實際經過script的方式加載。那浮如今我腦中的第一個問題天然是,小程序是如何實現js模塊的引用的呢?json

小程序的js模塊加載機制

以一個簡單的demo爲例,pages/home/index.js與pages/home/common.js,前者引入後者。小程序

pages/home/index.js:微信小程序

import boom from './common';
Page({});
複製代碼

pages/home/common.js:緩存

export default 'boom';
複製代碼

經小程序處理後,結果以下>>>>bash

pages/home/index.js:

define("pages/home/index.js", function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,fetch,XMLHttpRequest,WebSocket,webkit,WeixinJSCore,Reporter,print,URL,DOMParser,upload,preview,build,showDecryptedInfo,syncMessage,checkProxy,showSystemInfo,openVendor,openToolsLog,showRequestInfo,help,showDebugInfoTable,closeDebug,showDebugInfo,__global,WeixinJSBridge){ 'use strict';

    var _common = require('./common');

    var _common2 = _interopRequireDefault(_common);

    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

    Page({});
});
複製代碼

pages/home/common.js:

define("pages/home/common.js", function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,fetch,XMLHttpRequest,WebSocket,webkit,WeixinJSCore,Reporter,print,URL,DOMParser,upload,preview,build,showDecryptedInfo,syncMessage,checkProxy,showSystemInfo,openVendor,openToolsLog,showRequestInfo,help,showDebugInfoTable,closeDebug,showDebugInfo,__global,WeixinJSBridge){ 'use strict';

    Object.defineProperty(exports, "__esModule", {
      value: true
    });
  
    exports.default = 'boom';
});
複製代碼

可見小程序對這份代碼作了es6>es5的轉換(固然前提是要在項目設置中打開容許),並將其處理成類amd的模式。那麼小程序是如何處理define及require的呢?

由於代碼在執行時全局變量define和局域變量require已存在,因此咱們能夠在代碼中打印它們出來,並順勢找到這兩段代碼定義的位置。它們都位於WAService.js。

define:

代碼代表,全部js都以路徑-模塊的鍵值對的方式存在了某全局變量c裏。模塊有兩個屬性,status和factory。其中status暫爲1,表明模塊還沒有加載;factory即被閉包在函數中的模塊內容。

require:

能夠看到require可分爲三步:

  1. 從全局變量c中讀出define裏定義的模塊對象(即當前的t)。

  2. 如status爲1,則初始化模塊;不然直接返回t.exports。

  3. 加載模塊

    ①將status的值置爲2,表示該模塊已被初始化。

    ②調用t.factory(即r(...)這一步)加載模塊,並將結果賦給t.exports。

    仔細看看r()這一步,有傳入三個入參,分別對應define中的require, module及exports。第一個入參,i(e),它到底執行了什麼呢?答案就在require的上面一個代碼塊中(line 37005)。它對模塊的存在性作了校驗,若讀不到模塊,會拋出cant find module xxx的異常。它的返回值就是require函數。

    ③當一段js模塊加載完成後,其模塊對象會變成

    {
        status: 2,
        factory: t,
        exports: t裏導出的值
    }
    複製代碼

因此,這其實就是典型的模塊加載思路,我以爲也與webpack打包模塊的處理方式十分類似,保證每份js模塊只在被第一次引用時被初始化一次,並將結果緩存全局以供其餘模塊往後使用。

js引入流程

通用加載

瞭解完小程序的js模塊加載機制,再將目光移回page-frame.html~

不難發現小程序經過script標籤引入全部js,並按照其餘js > 頁面js >app.js的順序。以後會當即執行require('app.js')和require('各頁面.js')來註冊app和頁面。

不過,你們有好奇過這幾塊script標籤是如何生成的嗎?它們是一開始就存在嗎?只要咱們接着往下看,注意以後的script標籤,能夠留意到這樣一段代碼:

image-20181208010815326

重要的部分我大概圈了出來~從中發現,其實上段代碼中小程序引入的全部js script,都是經過這段終極script製造出來的喔。它的行動過程大概分爲兩步:

  1. 經過document.head.appendChild()動態append全部須要加載的js,如<script src="pages/home/index"></script>`(小小留意一下順序問題,app.js最後才被add script)
  2. 待全部需加載js的script添加完畢後,會在最後append進require('app.js')和require('各頁面.js')的代碼塊來執行對應板塊的代碼!~

因此這就是爲何app.js和各page.js在引入完成後,就會自動執行的緣由~

組件加載

組件是小程序晚些時候提供的能力,咱們也能夠將其視爲一種特殊的頁面。以下圖,可見組件加載方式也是與頁面同樣同樣的~(固然實現不同)。

好的,目前爲止,普通頁面的加載過程應該已一目瞭然~那天然引入下一個問題,小程序是如何處理分包代碼加載的呢,大機率也是在前往分包頁面後,將分包代碼append script的把?

分包加載

那麼頁面結構保持不變,不過在app.json中,將pages/pageA劃入subPackages的分包範疇。再次刷新代碼:

在home頁時,能夠看到document的結構中確實只有app.js和home.js,沒有引入pageA.js:

而後navigateTo pageA頁,再次檢閱document結構,發現符合猜測:

原代碼的基礎上多了pageA的script,以及又一大坨代碼段,粗略看起來是處理wxml的nodes外加與處理加載相關的其餘代碼…不過以前我覺得也會顯性經過appendrequire('pages/pagesA/index.js')代碼塊的方式來執行pageA.js頁面,如今看來並無。

總結

①page-frame.html體現了小程序處理頁面的顯性流程。

②各js模塊經過script標籤引入,經過類AMD方式進行加載執行。

③app.js和page.js以及component.js會在引入後當即執行。

emmm…雖然知道了這些我很開心 可是貌似對開發也麼有什麼太大的幫助>.< 不過總比兩眼一抹黑的狀態要好啦,而且想作小程序打包時,知道這些會有些許裨益~!Happy wxa coding!

相關文章
相關標籤/搜索