@chatui/core
Version:
The React library for Chatbot UI
124 lines (111 loc) • 3.77 kB
JavaScript
// 缓存已加载的脚本 Promise
var scriptCache = new Map();
/**
* 动态导入外部脚本
* @param url 脚本地址
* @param name 全局变量名
* @param options 配置项
* @returns Promise<T> 返回全局变量的值
*/
export function importScript(url, name) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _options$timeout = options.timeout,
timeout = _options$timeout === void 0 ? 5000 : _options$timeout,
_options$retry = options.retry,
retry = _options$retry === void 0 ? 3 : _options$retry,
_options$retryDelay = options.retryDelay,
retryDelay = _options$retryDelay === void 0 ? 1000 : _options$retryDelay,
_options$cache = options.cache,
cache = _options$cache === void 0 ? false : _options$cache;
// 生成缓存键
var cacheKey = "".concat(url, "::").concat(name);
// 检查缓存
if (cache && scriptCache.has(cacheKey)) {
return scriptCache.get(cacheKey);
}
// 内部加载函数,封装重试逻辑
function attemptLoad(retriesLeft, currentDelay) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.src = url;
script.async = true;
script.crossOrigin = 'anonymous';
var timeoutId;
// 竞态保护:防止 Promise 被多次 resolve/reject(超时与 load/error 事件竞态)
var isResolved = false;
// 清理函数
var cleanup = function cleanup() {
if (timeoutId) {
clearTimeout(timeoutId);
}
script.onload = null;
script.onerror = null;
// 清理 script 标签
// try-catch 必要:防止 script 已被其他代码删除、页面卸载等异常场景
try {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
} catch (e) {
// 忽略清理错误
}
};
// 错误处理
var handleError = function handleError(errMsg) {
if (isResolved) return;
isResolved = true;
cleanup();
// 如果还有重试次数,进行重试
if (retriesLeft > 0) {
// 指数退避策略:每次重试延迟时间翻倍(如 1s -> 2s -> 4s -> 8s)
setTimeout(function () {
attemptLoad(retriesLeft - 1, currentDelay * 2).then(resolve).catch(reject);
}, currentDelay);
} else {
// 最后一次失败,从缓存中删除
if (cache) {
scriptCache.delete(cacheKey);
}
reject(new Error(errMsg));
}
};
// 设置超时
if (timeout > 0) {
timeoutId = window.setTimeout(function () {
handleError("Script load timeout: ".concat(url));
}, timeout);
}
// 监听加载事件
script.onload = function () {
if (isResolved) return;
isResolved = true;
cleanup();
var globalVar = window[name];
if (globalVar) {
// 删除全局变量
try {
delete window[name];
} catch (e) {
// 某些全局变量可能无法删除(如只读属性)
window[name] = undefined;
}
resolve(globalVar);
} else {
handleError("Script loaded but global variable \"".concat(name, "\" not found"));
}
};
script.onerror = function () {
handleError("Failed to load script: ".concat(url));
};
// 添加到 DOM
document.head.appendChild(script);
});
}
// 创建加载 Promise
var loadPromise = attemptLoad(retry, retryDelay);
// 存入缓存
if (cache) {
scriptCache.set(cacheKey, loadPromise);
}
return loadPromise;
}