微信小程序的require機制淺析

(注: 本文中所列微信小程序工具代碼,並不是爲微信小程序原始代碼,而是學習概括的示意代碼)json

在學習開發微信小程序中, 分析總結了最近版本微信小程序模塊化的函數 require的加載與初始化模塊機制,
概括說來,小程序JS模塊加載可分爲兩大步驟:
一,JS模塊加載
二,JS模塊初始化
具體以下:小程序

一, JS模塊加載:一次性加載所有JS, 但並不必定當即執行.

先提一提微信小程序架構: 類瀏覽器 -> HTTP本地服務 -> 雲端服務

微信小程序運行的架構,基本上是瀏覽器 -> HTTP本地服務 -> 雲端服務, HTTP本地服務用來讀取本地文件或者代理雲端的文件資源。
讀取項目中JS文件, 是由HTTP本地服務取本地存儲的腳本文件.微信小程序

彷佛比較簡單,一個HTML 引用全部JS文件

既然採用了這種架構,那微信小程序就相似瀏覽器那樣,藉助一個HTML頁面來引用加載全部的JS文件。(注:這同NODE.JS的方式區別)
在小程序開發開具的HTTP服務部分代碼,能夠看到這個服務幹了這件事情:
微信小程序包目錄下面全部.js文件, 會按<script src="../xxx.js"> 方式插入生成一個HTML文件,而後相似瀏覽器方式加載.瀏覽器

讓HTTP本地服務配合,對JS文件做的包裝手法

但是事情並未結束,這種方式一加載,全部js文件都會當即執行,亂糟糟生成一團,怎麼可能..那require函數又拿來幹什麼呢?
原來這兒,HTTP服務在返回.JS文件內容的,給腳本內容包裝上了一層: define函數服務器

代理服務部分代碼:
(projectManager.js)
function getScripts(projInfo, callback) {
  ...
    fs.readFile(fname, 'utf8', function(err, scripts) {
        ....    
        scripts = 'define("' + moduleName + '", function(require, module, exports, ' + noBrowserStr +
        '){ ' + scripts + '\n});',
        needRequire && (scripts += 'require("' + moduleName + '")'), //page頁面js文件,會添加上require本身,加載後當即初始化。
        .....
        callback(null, scripts) //scripts串內容做爲HTTP GET的返回

define函數很是簡單,大體以下:微信

......
    var 
    ......
    moduleList = {}; 
    define = function(moduleName, factory) {  //define是全局函數,每一個JS文件都默認會調用. 
        moduleList[moduleName] = { status: status1, factory: factory }
    };

從上面代碼看出,,這樣一來,每加載一個JS文件,只是將其文件名與腳本內容串加入了內存中的一個變量保存,並未執行。 注意,這就與普通的HTML 腳本引用加載當即執行徹底不一樣了.架構

接下來,就輪到微信小程序的require函數出場了。app

二, JS模塊初始化:按需遞歸式require初始化

先看看微信小程序require函數的定義:模塊化

....
    require = function(moduleName) {       
        ....
        var module = moduleList[moduleName]; //define函數調用時爲moduleList賦的值
        .....
        if (module.status === status1) {  
            //若是未初始化,則初始化
            var factory = module.factory,  //這個factory就是這個JS文件的腳本.
            obj = { exports: {} }, u = void 0;
            factory && (u = factory(o(moduleName), obj, obj.exports)), module.exports = obj.exports || u, module.status = status2
        }
        return module.exports
    }

從上面能夠看出, require函數只是經過模塊名,從內存中獲取腳本內容執行,並置標誌以保證只執行一次.函數

再精簡一下:

require --調用-> factory --->模塊中可能再require另外一個模塊...

這樣就是一個典型的遞歸結構。

三,補充一下:頁面js 其實也是被require函數加載

所謂頁面JS,,就是在app.json中註冊的page的js, 它們並無被其它JS require方式引用,
那麼它們在何時初始化?
回到以前本地代理服務器的代碼,留意下面一點:

代理服務部分代碼:
(projectManager.js)
function getScripts(projInfo, callback) {
  ...
    fs.readFile(fname, 'utf8', function(err, scripts) {
        ....    
        //page頁面js文件,needRequire值爲TRUE,會添加上require本身
        needRequire && (scripts += 'require("' + moduleName + '")'), 
        .....

原來它們仍是使用require函數初始化,並且是加載後當即執行。

目前一般微信小程序代碼結構不會太複雜,但隨着產品的發展,需求的增長, 代碼結構可能愈來愈複雜,愈來愈注意模塊化.同時,如何將舊有JS模塊在微信小程序中重用,這也是個重要話題。 因此深刻理解微信小程序的JS模塊化機制也是頗有價值的.

相關文章
相關標籤/搜索