也许道理就是异步加载一堆剧本文件,个人项目能够尝尝,企业项目运用请深图远虑后再举行尝试。
我相识到的要领来自于《javascript设想形式》,作者是张容铭,由于以为这个挺好玩的,给人人分享一下。
既然要直接在网页上完成模块化,一定须要异步增加剧本文件,所以须要处理两个贫苦的题目:
- 依靠的模块也有依靠怎么办
- 怎样晓得异步增加的js文件加载的状况
//main.js 不必关注细节,疾速相识下挪用体式格局即可
m.module(['dom/index'], function (dom) {
var test = document.getElementById('test')
console.log(dom(test).attr('id'))
dom(test).css({
'background': '#000',
'color': '#fff'
})
})
......
//dom/css.js
m.module('dom/css', ['shared/util'], function (util) {
return function (ele, css, value) {
if (util.isString(css)) {
if (util.isNumber(value)) {
return ele.style.css = value
}
return ele.style.css
} else {
for (var k in css) {
ele.style[k] = css[k]
}
}
}
})
......
//shared/util.js
m.module('shared/util', function () {
return {
isNumber: function (num) {
return num === (0 || num) && num.constructor === Number
},
isString: function (str) {
return str === ("" || str) && str.constructor === String
}
}
})
下面就最先完成这个暴露出来的module函数
遵守规则
将模块的完成隐蔽起来,建立一个闭包
(function(m){
var m = m()
})(function(){
window.m = {}
})
东西函数
增加两个东西函数,loadScript和getUrl
//加载剧本
var loadScript = function (src) {
var _script = document.createElement('script')
_script.type = 'text/javascript'
_script.async = true
_script.src = src
document.getElementsByTagName('head')[0].appendChild(_script)
},
//为地点增加一个.js
getUrl = function (moduleName) {
return String(moduleName).replace(/\.js$/g, '') + '.js'
}
module函数的完成
经由过程上面的图片示例能够相识到,module函数包含了建立和挪用模块的功用,它具有三个参数
- url 地点
- deps 数据类型为数组的依靠模块
- callback 该模块的主函数
猎取参数
m.module=function(){
var args = [].slice.call(arguments),
//取末了一个参数,即callback
callback = args.pop(),
//猎取依靠,且数据类型为数组
deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [],
//地点
url = args.length ? args.pop() : null
...
这就是完全module函数的完成,初看很庞杂,别急,module的症结就在于下面的两个函数(loadModule和setModule),通常异步道理都是在和大脑刁难,习气就是新世界的大门,不要拘泥于浏览递次
m.module = function () {
var args = [].slice.call(arguments),
callback = args.pop(),
deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [],
url = args.length ? args.pop() : null
params = [],//依靠模块序列,主函数(回调函数)的运用的参数
depsCount = 0,//该模块未加载终了的依靠数目
i = 0
if (deps.length) {
while (i < deps.length) {
//闭包保留i
(function (i) {
//如许每一个剧本实行的module都邑有一个depsCount
depsCount++
//loadModule初始化是不会挪用它的回调函数(缓冲器)的(能够先翻到下面看loadModule的完成)
//但它会把回调函数增加到moduleCache中去,同时加载该依靠的剧本
loadModule(deps[i], function (mod) {
//这里的mod是依靠模块的输出
params[i] = mod
//即是0的时刻就会实行本身的回调
depsCount--
if (depsCount === 0) {
//将依靠模块的输出增加到callback的参数中,如许主函数就能够直接运用参数举行挪用
setModule(url, params, callback)
}
})
})(i)
i++
}
} else {
//一旦依靠走到底部,也就是一个剧本文件里的模块没有了依靠(能够先看看下面setModule)
//loadModule初始化增加到moduleCache的回调就会实行,而depsCount就会-1
setModule(url, [], callback)
}
}
假如没有依靠的话,会直接实行setModule,该模块假如是被依靠的模块,就会挪用loadModule缓存的缓冲器,也就是它的回调函数
能够先看看loadModule和setModule的完成
if(deps.length){
...
}else{
setModule(url, [], callback)
}
增加一个moduleCache变量,用于缓存模块
//闭包内部
var moduleCache = {}
var setModule = function (moduleName, params, callback) {
var _module, fn
if (moduleCache[moduleName]) {
_module = moduleCache[moduleName]
_module.status = 'loaded'
//export是模块的输出
_module.exports = callback ? callback.apply(_module, params) : null
while (fn = _module.onload.shift()) {
//实行回调,并将本身的模块输出到缓冲器中
fn(_module.exports)
}
} else {
callback && callback.apply(null, params)
}
}
//这里参数callback不是主函数,而是保留的缓冲器,细致翻回module的完全函数
var loadModule = function (moduleName, callback) {
var _module
//已初始化
if (moduleCache[moduleName]) {
_module = moduleCache[moduleName]
if (_module.status === 'loaded') {
//有就直接从moduleCache缓存中猎取
setTimeout(callback(_module.exports), 4)
} else {
_module.onload.push(callback)
}
} else {
//初始化
moduleCache[moduleName] = {
//地点,也能够叫模块称号
moduleName: moduleName,
status: 'loading',
//该模块return 的输出
exports: null,
onload: [callback]
}
//增加剧本
loadScript(getUrl(moduleName))
}
}
第一次写文章,假如以为不好明白或许有行文不严谨的处所能够发下批评或许私信我修正
有协助的话给我个赞哦