dynamicLoadScript
snippet 动态加载 script src,支持并发加载相同 url 不冲突。
| JavaScript |
|---|
| /**
* 动态加载 script src,支持并发加载相同url不冲突。
* @param src
* @returns {Promise<unknown>}
*/
const loadingScripts = {} // 保存正在加载的 script 的 Promise
const dynamicLoadScript = (src) => {
return new Promise((resolve, reject) => {
// 检查是否已经在加载中
if (loadingScripts[src]) {
// 已经在加载中,等待 Promise 完成
// console.warn('[dynamicLoadScript] wait loading:', src)
loadingScripts[src].then(resolve).catch(reject)
return
}
// 检查是否已经存在该 script
const existingScript = document.getElementById(src)
if (existingScript) {
// console.warn('[dynamicLoadScript] is existed:', src)
resolve() // script 已经加载,直接 resolve
return
}
// console.log('[dynamicLoadScript] loading:', src)
// 创建 script 标签并开始加载
const script = document.createElement('script')
script.src = src
script.id = src
let loadResolver // 保存 resolve 函数,以便在外部访问
let loadRejecter // 保存 reject 函数,以便在外部访问
const loadPromise = new Promise((res, rej) => {
loadResolver = res
loadRejecter = rej
})
loadingScripts[src] = loadPromise // 保存 promise
script.onload = function () {
this.onerror = this.onload = null
delete loadingScripts[src] // 加载完成后删除
loadResolver() // Resolve 内部的 Promise
resolve() // Resolve 外部的 Promise
}
script.onerror = function (e) {
this.onerror = this.onload = null
delete loadingScripts[src] // 加载失败后删除
const error = new Error(`[dynamicLoadScript] load script error: ${src}`)
console.error('[dynamicLoadScript] error:', e)
loadRejecter(error) // Reject 内部的 Promise
reject(error) // Reject 外部的 Promise
}
document.body.appendChild(script)
})
}
|