sea.js源码(seajs.request()请求资源)

这里是从sea.js 源码中的 util-request.js,用于向服务器请求和加载资源到页面,在sea.js 中,其在Module.fetch() 中被调用。建议大家先行阅读
sea.js源码(Module.js核心代码),对本篇的理解会更加顺畅。

前提引入

我们来看 Module.fetch() 中的一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function sendRequest() {
seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset, emitData.crossorigin)
}

function onRequest(error) {
delete fetchingList[requestUri]
fetchedList[requestUri] = true

// Save meta data of anonymous module
if (anonymousMeta) {
Module.save(uri, anonymousMeta)
anonymousMeta = null
}

// Call callbacks
var m, mods = callbackList[requestUri]
delete callbackList[requestUri]
while ((m = mods.shift())) {
// When 404 occurs, the params error will be true
if(error === true) {
m.error()
}
else {
m.load()
}
}
}

这段代码大体的意思就是 sendRequest() 调用后会 执行seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset, emitData.crossorigin)。即引出我们本篇的主人公,seajs.request() 。这里我们向seajs.request 传入了四个参数:

  • requestUri: 资源的请求路径
  • onRequest : 这里便是上面这段代码的onRequest 函数,是我们加载完执行的回调
  • charset : 文件编码
  • crossorigin :: 跨域属性,允许配置元素获取数据的 CORS 请求是否需要携带凭证。

seajs.request(url, callback, charset, crossorigin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* util-request.js - The utilities for requesting script and style files
* ref: tests/research/load-js-css/test.html
*/
if (isWebWorker) {
function requestFromWebWorker(url, callback, charset, crossorigin) {
// Load with importScripts
var error
try {
importScripts(url)
} catch (e) {
error = e
}
callback(error)
}
// For Developers
seajs.request = requestFromWebWorker
}
else {
var doc = document
var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement
var baseElement = head.getElementsByTagName("base")[0]

var currentlyAddingScript

function request(url, callback, charset, crossorigin) {
var node = doc.createElement("script")

if (charset) {
node.charset = charset
}

if (!isUndefined(crossorigin)) {
node.setAttribute("crossorigin", crossorigin)
}

addOnload(node, callback, url)

node.async = true
node.src = url

// For some cache cases in IE 6-8, the script executes IMMEDIATELY after
// the end of the insert execution, so use `currentlyAddingScript` to
// hold current node, for deriving url in `define` call
currentlyAddingScript = node

// ref: #185 & http://dev.jquery.com/ticket/2709
baseElement ?
head.insertBefore(node, baseElement) :
head.appendChild(node)

currentlyAddingScript = null
}

function addOnload(node, callback, url) {
var supportOnload = "onload" in node

if (supportOnload) {
node.onload = onload
node.onerror = function() {
emit("error", { uri: url, node: node })
onload(true)
}
}
else {
node.onreadystatechange = function() {
if (/loaded|complete/.test(node.readyState)) {
onload()
}
}
}

function onload(error) {
// Ensure only run once and handle memory leak in IE
node.onload = node.onerror = node.onreadystatechange = null

// Remove the script to reduce memory leak
if (!data.debug) {
head.removeChild(node)
}

// Dereference the node
node = null

callback(error)
}
}

// For Developers
seajs.request = request

}

整段代码的流程如下:

  • ==》 在文档的head中动态的添加一个script标签,同时设置一个async属性为true,这样是为了异步加载这个文件
  • ==》 执行js文件脚本
    • 在seajs中,我们的js文件要通过define() 包装定义成一个模块,执行脚本就是调用 define()
    • define() 中解析依赖模块和同步依赖(即 require() )的模块,通过 define() 传递过来的参数形成一个 Module 模块。
    • (有关define()的详细讲解,有兴趣的同学可以查看seajs源码(define,exec定义和执行模块代码)
  • == 》 执行我们给脚本 监听的 onload() 事件,在onload中我们便执行了回调函数。