-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathloader.js
More file actions
201 lines (168 loc) · 5.57 KB
/
loader.js
File metadata and controls
201 lines (168 loc) · 5.57 KB
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/**
* @preserve Tiny-Loader: A small loader that load CSS/JS in best way for page performanceIs.
*
* @version 1.0.1
* @copyright The Youzan Limited [All Rights Reserved]
* @license MIT License (see LICENSE.txt)
*/
(function(window, document) {
'use strict';
// cssExpr 用于判断资源是否是css
var cssExpr = new RegExp('\\.css');
var nHead = document.head || document.getElementsByTagName('head')[0];
// `onload` 在WebKit < 535.23, Firefox < 9.0 不被支持
var isOldWebKit = +navigator.userAgent
.replace(/.*(?:AppleWebKit|AndroidWebKit)\/?(\d+).*/i, '$1') < 536;
// 判断对应的node节点是否已经载入完成
function isReady(node) {
return node.readyState === 'complete' || node.readyState === 'loaded';
}
// loadCss 用于载入css资源
function loadCss(url, setting, callback) {
var node = document.createElement('link');
node.rel = 'stylesheet';
addOnload(node, callback, 'css');
node.async = true;
node.href = url;
nHead.appendChild(node);
}
// loadJs 用于载入js资源
function loadJs(url, setting, callback) {
var node = document.createElement('script');
node.charset = 'utf-8';
addOnload(node, callback, 'js');
node.async = !setting.sync;
node.src = url;
nHead.appendChild(node);
}
// 在老的webkit中,因不支持load事件,这里用轮询sheet来保证
function pollCss(node, callback) {
var isLoaded;
if (node.sheet) {
isLoaded = true;
}
setTimeout(function() {
if (isLoaded) {
// 在这里callback 是为了让样式有足够的时间渲染
callback();
} else {
pollCss(node, callback);
}
}, 20);
}
// 用于给指定的节点绑定onload回调
// 监听元素载入完成事件
function addOnload(node, callback, type) {
var supportOnload = 'onload' in node;
var isCSS = type === 'css';
// 对老的webkit和老的firefox的兼容
if (isCSS && (isOldWebKit || !supportOnload)) {
setTimeout(function() {
pollCss(node, callback);
}, 1);
return;
}
if (supportOnload) {
node.onload = onload;
node.onerror = function() {
node.onerror = null;
window._cdnFallback(node);
};
} else {
node.onreadystatechange = function() {
if (isReady(node)) {
onload();
}
};
}
function onload() {
// 执行一次后清除,防止重复执行
node.onload = node.onreadystatechange = null;
node = null;
callback();
}
}
// 资源下载入口,根绝文件类型的不同,调用loadCss或者loadJs
function loadItem(url, list, setting, callback) {
// 如果加载的url为空,就直接成功返回
if (!url) {
setTimeout(function() {
onFinishLoading();
});
return;
}
if (cssExpr.test(url)) {
loadCss(url, setting, onFinishLoading);
} else {
loadJs(url, setting, onFinishLoading);
}
// 每次资源下载完成后,检验是否结束整个list下载过程
// 若已经完成所有下载,执行回调函数
function onFinishLoading() {
var urlIndex = list.indexOf(url);
if (urlIndex > -1) {
list.splice(urlIndex, 1);
}
if (list.length === 0) {
callback();
}
}
}
function doInit(list, setting, callback) {
var cb = function() {
callback && callback();
};
list = Array.prototype.slice.call(list || []);
if (list.length === 0) {
cb();
return;
}
for (var i = 0, len = list.length; i < len; i++) {
loadItem(list[i], list, setting, cb);
}
}
// 判断当前页面是否加载完
// 加载完,立刻执行下载
// 未加载完,等待页面load事件以后再进行下载
function ready(node, callback) {
if (isReady(node)) {
callback();
} else {
// 1500ms 以后,直接开始下载资源文件,不再等待load事件
var timeLeft = 1500;
var isExecute = false;
window.addEventListener('load', function() {
if (!isExecute) {
callback();
isExecute = true;
}
});
setTimeout(function() {
if (!isExecute) {
callback();
isExecute = true;
}
}, timeLeft);
}
}
// 暴露出去的Loader
// 提供async, sync两个函数
// async 用作异步下载执行用,不阻塞页面渲染
// sync 用作异步下载,顺序执行,保证下载的js按照数组顺序执行
var Loader = {
async: function(list, callback) {
ready(document, function() {
doInit(list, {}, callback);
});
},
sync: function(list, callback) {
ready(document, function() {
doInit(list, {
sync: true
}, callback);
});
}
};
window.Loader = Loader;
return Loader;
})(window, document);