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!

相关文章
相关标签/搜索