theme: fancy
在实际的开发过程中,我们有时候会遇到动态加载静态资源的需要,这当然是一个很简单的需求,但是如何做到更优雅的实现呢?
参考优秀的vue-ueditor-wrap库
首先,我们可以采用回调函数的方法实现
function loadScript(link, cb){
if(typeof cb !== 'function'){
cb = function(){}
}
const script = document.createElement('script');
srcipt.src = link;
script.onload = cb;
script.onerror = reject;
document.getElementsByTagName('head')[0].appendChild(script);
}
loadScript('XXX.js', loadScript('X1.js', /*...*/ ))
上面的方法,如果依赖的js比较多,写出来的代码就会很丑。
通过Promise来实现,会让我们的代码看起来更加优雅
var cache = {}
function loadScript(link){
if(cache[link]) return Promise.resolve()
return new Promise((resolve, reject)=>{
function success(){
cache[link] = true
resolve()
}
function fail(){
reject(link)
}
const script = document.createElement('script');
srcipt.src = link;
script.onload = success;
script.onerror = fail;
document.getElementsByTagName('head')[0].appendChild(script);
})
}
实现加载资源的函数
// 依次加载依赖的 JS 文件
// 通过reduce将要加载的js通过promise链串联起来
// 动态创建 script 是先加载完的先执行,所以不可以一次性创建所有资源的引入脚本
// 根据promise的异常传透原理, 如果有一个加载错误,后面的js就不再加载,并将错误的js连接直接抛出
function asyncSeries(funs){
return funs.reduce((promise, fun) => promise.then(fun), Promise.resolve());
}
function loadStaticSource(links:[]){
return new Promise((resolve, reject)=>{
asyncSeries(jsLinks.map((link) => () => loadScript(link)))
.then(resolve)
.catch(reject);
})
}
测试一下,效果不错!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var cache = {}
function loadScript(link) {
if (cache[link]) return Promise.resolve()
return new Promise((resolve, reject) => {
function success() {
cache[link] = true
resolve()
}
function fail() {
reject(link)
}
const script = document.createElement('script');
script.src = link;
script.onload = success;
script.onerror = fail;
document.getElementsByTagName('head')[0].appendChild(script);
})
}
function asyncSeries(funs) {
return funs.reduce((promise, fun) => promise.then(fun), Promise.resolve());
}
function loadStaticSource(links) {
return new Promise((resolve, reject) => {
let p = asyncSeries(links.map((link) => () => loadScript(link)))
p.then(resolve)
.catch(reject);
})
}
const links = ['https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js', 'yy.js', 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js'];
const links1 = ['https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js', 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js']
loadStaticSource(links).then(() => {
console.log("资源加载完成")
}, (link) => {
console.log(link + "资源加载错误")
})
loadStaticSource(links1).then(() => {
console.log("资源加载完成")
}, (link) => {
console.log(link + "资源加载错误")
})
</script>
</body>
</html>