sea.js想处理的题目
恼人的定名争执
啰嗦的文件依靠
对应带来的优点 Sea.js 带来的两大优点:
经由历程 exports 暴露接口。这意味着不须要定名空间了,更不须要全局变量。这是一种完全的定名争执处理方案。
经由历程 require 引入依靠。这能够让依靠内置,开辟者只需体贴当前模块的依靠,其他事变 Sea.js 都邑自动处理好。对模块开辟者来讲,这是一种很好的 关注度星散,能让顺序员更多地享用编码的兴趣。
API速查
1. seajs.config
2. seajs.use
3. define
4. require
5. require.async
6. exports
7. module.exports
sea.js的实行历程
启动
用script
标签引入sea.js文件,seajs.config(data)
启动设置函数,config
函数会会兼并一切config
设置,seajs.use = function(ids, callback)
,启用主剧本
运转历程
主剧本启动以后,起首应用request
模块要求主剧本(天生script标签插进去head标签中),然后依据正则剖析模块define
的依靠,并对依靠递归剖析其依靠。
在运转历程当中,经由历程监听发布者形式,体系内置了8个事宜,可用于开辟插件。
resolve -- 将 id 剖析成为 uri 时触发
load -- 最先加载文件时触发
fetch -- 详细猎取某个 uri 时触发
request -- 发送要求时触发
define -- 实行 define 要领时触发
exec -- 实行 module.factory 时触发
config -- 挪用 seajs.config 时触发
error -- 加载剧本文件涌现 404 或其他毛病时触发
全局挂载
一切相干数据末了悉数挂载在window.seajs
下,包含要领及模块数据。
小学问点
exports与module.exports
exports 仅仅是 module.exports 的一个援用。在 factory 内部给 exports 从新赋值时,并不会转变 module.exports 的值。因而给 exports 赋值是无效的,不能用来变动模块接口。
//源码以下
// Exec factory
var factory = mod.factory;
var exports = isFunction(factory) ?
factory.call(mod.exports = {}, require, mod.exports, mod) :
factory
关于动态依靠
有时会愿望能够运用 require 来举行前提加载:
if (todayIsWeekend)
require("play");
else
require("work");
但请切记,从静态剖析的角度来看,这个模块同时依靠 play 和 work 两个模块,加载器会把这两个模块文件都下载下来。 这类情况下,引荐运用 require.async 来举行前提加载。
//sea.js源码以下
require.async = function(ids, callback) { //可传入回调函数
Module.use(ids, callback, uri + "_async_" + cid()) //——async_英语标识这个剧本是异步加载的,cid用于消灭缓存
return require //返回require轻易链式挪用
}
在开辟时,Sea.js 是怎样晓得一个模块的详细依靠呢?
a.js
define(function(require, exports) {
var b = require('./b');
var c = require('./c');
});
Sea.js 在运转 define 时,接收 factory 参数,能够经由历程 factory.toString() 拿到源码,再经由历程正则婚配 require 的体式格局来获得依靠信息。依靠信息是一个数组,比方上面 a.js 的依靠数组是:[‘./b’, ‘./c’]
//源码以下
// Parse dependencies according to the module factory code
if (!isArray(deps) && isFunction(factory)) {
deps = typeof parseDependencies === "undefined" ? [] : parseDependencies(factory.toString()) //parseDependencies是应用正则剖析依靠的一个函数
}
时刻动身函数Emit
// Emit event, firing all bound callbacks. Callbacks receive the same
// arguments as `emit` does, apart from the event name
var emit = seajs.emit = function(name, data) {
var list = events[name]
if (list) {
// Copy callback lists to prevent modification
list = list.slice()
// Execute event callbacks, use index because it's the faster.
for(var i = 0, len = list.length; i < len; i++) {
list[i](data)
}
}
return seajs
}
重要看这个部份list = list.slice()
,解释是防备拷贝该时刻的回调函数,防备修正,疑心了一下。
原因是Javascript中赋值时,关于援用数据范例,都是传地点。
所以这里,假如想防备触发事宜的历程当中回调函数被变动,必需对这个list数组举行拷贝,而并不是只是将list指向events[name]的地点。
依据debug值设置是不是删除动态插进去的剧本
// Remove the script to reduce memory leak
if (!data.debug) {
head.removeChild(node)
}
这里思索了蛮久,为何能够删除动态插进去的剧本?如许剧本还会见效吗?
起首,必需相识计算机内存分为
静态数据区 (用来寄存顺序中初始化的全局变量的一块内存地区)
代码区 (一般用来寄存实行代码的一块内存地区)
栈区 (栈在历程运转时发生,一个历程有一个历程栈。栈用来存储顺序暂时寄存的局部变量,即函数内定义的变量 不包含static 范例的。函数被挪用时,他的形参也会被压栈。
堆区 (用于寄存历程运转中被动态分派的内存段,它的大小并且不牢固,可动态扩展。当历程挪用malloc等分派内存时,新分派的内存被动态的添加到堆上(堆被扩展),当应用free等函数开释内存时,被开释的‘ 内存从堆中剔除)
这些在Javascript中都被屏障了,大部份时刻我们都不须要斟酌,然则假如要深切相识的话,则是必需要晓得的学问。
起首HTML文档中的JS剧本在计算机中作为指令被读入内存,以后最先实行,CPU最先一条一条指令读取,比方,读取到var cool = "wilson"
时,就会在内存中分派一个6字符大小的内存,一个function
也一样会在内存中占有肯定大小。所以,当指令悉数运转完以后,指令自身实在已没有用了,然则依然给占有了一部份内存。
当你点击按钮触发一个回调函数时,并不是去读取指令,而是读取内存中这个回调函数的地点。所以删除这些动态加载的JS文件是没有题目的。
ID 和途径婚配准绳
所谓 ID 和途径婚配准绳 是指,运用 seajs.use 或 require 举行援用的文件,假如是签字模块(即定义了 ID 的模块),会把 ID 和 seajs.use 的途径名举行婚配,假如一致,则准确实行模块返回效果。反之,则返回 null。
对 module.exports 的赋值须要同步实行,不能放在回调函数里。下面如许是不可的
// x.js
define(function(require, exports, module) {
// 毛病用法
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
});
//在 y.js 里有挪用到上面的 x.js:
// y.js
define(function(require, exports, module) {
var x = require('./x');
// 没法马上获得模块 x 的属性 a
console.log(x.a); // undefined
});
WilsonLiu’s blog首发地点:http://blog.wilsonliu.cn