# 判断JS是否加载,没加载则加载
# 思路
- 判断页面是否引用JS文件
- 监听 performance entry 变动
- 加载JS文件
# 代码
/**
* 判断JS是否加载,没加载则加载
* @param {Object} Options - 设置项.
* @param {string} Options.scriptName - 脚本文件名.
* @param {string} Options.cssFile - CSS备用路径.
* @param {string} Options.jsFile - JS备用路径.
* @param {string} Options.jsMethodName - JS方法名.
* @param {string} Options.isRelativePath - 是否相对路径.
* @return {Promise} 返回的Promise
*/
function LoadingJS(Options = {}) {
let PromiseJS = new Promise((resolve, reject) => {
/**
* 加载Css和Js文件
* @param {String} url - 请求地址
* @param {String} type - 请求类型
* @return {Promise}
*/
function addCssJsFile(url, type) {
if (window.loadCssJs === undefined) {
window.loadCssJs = {};
}
let promise = new Promise(function (resolve, reject) {
let element = null;
// 创建文件格式
switch (type) {
case "css":
element = document.createElement('link');
element.type = 'text/css';
element.rel = 'stylesheet';
element.href = url;
break;
case "js":
element = document.createElement('script');
element.type = "text/javascript";
element.src = url;
break;
default:
break;
}
// 绑定加载完毕事件
if (element.readyState) { //IE
element.onreadystatechange = function () {
if (element.readyState == "loaded" || element.readyState == "complete") {
element.onreadystatechange = null;
resolve(this.response);
}
};
} else { //Others
element.onload = function () {
resolve(this.response);
};
}
// 创建文件
if (!window.loadCssJs[url]) {
document.getElementsByTagName('head')[0].appendChild(element);
}
});
let fixPromise = promise;
if (!window.loadCssJs[url]) {
window.loadCssJs[url] = promise;
} else {
fixPromise = window.loadCssJs[url];
}
return fixPromise;
}
/**
* 监听 performance entry 变动
* @param {String} scriptName - 文件名
*/
function checkPerformanceEntries(scriptName) {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.name.includes(scriptName) && entry.entryType === 'resource') {
setTimeout(function(){
console.log(`${scriptName} loading complete.`);
resolve(`${scriptName} loading complete.`);
},0)
observer.disconnect(); // 停止监听
}
});
});
observer.observe({ entryTypes: ['resource'] });
}
/**
* Html 是否包含脚本
* @param {String} scriptName - 文件名
*/
function HtmlContainsScript(scriptName) {
let scripts = document.getElementsByTagName('script');
for (let i = 0; i < scripts.length; i++) {
// 获取引用文件路径
let fileSrc = scripts[i].src;
// 去除查询参数
let fileWithoutQuery = fileSrc.split('?')[0];
// 抽取文件名字
let filename = fileWithoutQuery.replace(/.*(\/|\\)/, "");
// 文件名字 与 脚本名字 对比
if (filename === scriptName) {
return true;
}
}
return false;
}
/**
* 获取当前文件的路径
*/
function getCurrentFilePath(){
let scriptUrl;
try {
throw new Error();
} catch (e) {
var stack = e.stack;
// 堆栈信息的格式可能因浏览器而异,以下是一个常见的格式
var scriptRegex = /(https?:\/\/[^\s]+?\/[^:\s]+):(\d+):(\d+)/;
var matches = stack.match(scriptRegex);
if (matches) {
scriptUrl = matches[1]; // 获取脚本的URL
}
}
if (scriptUrl) {
// 使用.replace()方法去掉URL末尾的文件名
scriptUrl = scriptUrl.replace(/(.*\/)[^/]+/, '$1');
// 或者使用.split()方法去掉URL末尾的文件名
// scriptUrl = scriptUrl.split('/').slice(0, -1).join('/');
}
return scriptUrl;
}
let scriptName = Options.scriptName;
if (HtmlContainsScript(scriptName)) {
if (window[Options.jsMethodName]) {
console.log(`${scriptName} loading complete.`);
resolve(`${scriptName} loading complete.`);
} else {
console.log(`${scriptName} is loading.`);
checkPerformanceEntries(scriptName);
}
} else {
console.log(`${scriptName} not loaded.`);
let scriptUrl = null;
if( Options.isRelativePath ){
scriptUrl = getCurrentFilePath();
}else{
scriptUrl = "";
}
addCssJsFile(`${scriptUrl + Options.cssFile}`, 'css');
addCssJsFile(`${scriptUrl + Options.jsFile}`, 'js').then(function(){
console.log(`${scriptName} loading complete.`);
resolve(`${scriptName} loading complete.`);
});
}
});
return PromiseJS;
}
LoadingJS({
scriptName: "swiper.min.js",
cssFile: "vendor/swiper/swiper-bundle.min.css",
jsFile: "vendor/swiper/swiper.min.js",
jsMethodName: "Swiper",
isRelativePath: true
});
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
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