如何避免依赖shared_library.js的JS组件重复注入deferred脚本?
解决共享库重复注入的问题
要避免shared_library.js被重复注入,核心是跟踪脚本的加载状态,而不是仅检查最终生成的window.MyLibrary(因为加载过程中这个对象还未存在)。以下是几种实用方案:
方案1:全局状态标记跟踪加载流程
在全局作用域设置一个标记,记录共享库的三种状态:未加载、加载中、已加载。每个组件先检查这个标记,再决定后续操作:
// first_widget.js 和 second_widget.js 共用的逻辑 var loadCallback = function () { // 使用 window.MyLibrary }; (function(document) { // 全局标记:跟踪共享库的加载状态 window._MyLibraryStatus = window._MyLibraryStatus || 'unloaded'; if (window._MyLibraryStatus === 'loaded') { // 库已加载完成,直接执行回调 loadCallback(); return; } if (window._MyLibraryStatus === 'loading') { // 库正在加载中,等待加载完成后执行回调 var checkInterval = setInterval(function() { if (window._MyLibraryStatus === 'loaded') { clearInterval(checkInterval); loadCallback(); } }, 50); return; } // 开始加载共享库 window._MyLibraryStatus = 'loading'; var script = document.createElement('script'); var firstScript = document.getElementsByTagName('script')[0]; script.src = 'https://example.com/shared_library.js'; script.defer = true; script.onload = function () { window._MyLibraryStatus = 'loaded'; loadCallback(); }; // 处理加载失败的情况(可选) script.onerror = function () { window._MyLibraryStatus = 'unloaded'; console.error('Failed to load shared_library.js'); }; firstScript.parentNode.insertBefore(script, firstScript); }(document));
方案2:检查DOM中已存在的脚本标签
直接查找DOM中是否已经存在指向shared_library.js的script标签,避免重复创建:
// first_widget.js 和 second_widget.js 共用的逻辑 var loadCallback = function () { // 使用 window.MyLibrary }; (function(document) { // 检查是否已经注入过该脚本 var existingScript = document.querySelector('script[src="https://example.com/shared_library.js"]'); if (existingScript) { // 脚本已存在,判断是否加载完成 if (window.MyLibrary) { loadCallback(); } else { // 脚本正在加载,监听其onload事件 existingScript.addEventListener('load', loadCallback); } return; } // 首次注入脚本 var script = document.createElement('script'); var firstScript = document.getElementsByTagName('script')[0]; script.src = 'https://example.com/shared_library.js'; script.defer = true; script.onload = loadCallback; firstScript.parentNode.insertBefore(script, firstScript); }(document));
方案3:用Promise统一管理加载状态(现代浏览器适用)
利用Promise的特性,将共享库的加载过程封装为一个全局Promise,多个组件可以共享这个Promise的状态:
// first_widget.js 和 second_widget.js 共用的逻辑 var loadCallback = function () { // 使用 window.MyLibrary }; (function(document) { // 全局Promise:共享库加载完成的Promise window._MyLibraryPromise = window._MyLibraryPromise || new Promise(function(resolve, reject) { var script = document.createElement('script'); var firstScript = document.getElementsByTagName('script')[0]; script.src = 'https://example.com/shared_library.js'; script.defer = true; script.onload = function () { resolve(window.MyLibrary); }; script.onerror = function () { reject(new Error('Failed to load shared_library.js')); }; firstScript.parentNode.insertBefore(script, firstScript); }); // 等待Promise完成后执行回调 window._MyLibraryPromise.then(loadCallback).catch(function(err) { console.error(err); }); }(document));
以上三种方案都能有效避免重复注入shared_library.js,其中方案3更符合现代JS的异步编程习惯,方案1和2兼容性更好,可根据实际场景选择。
内容的提问来源于stack exchange,提问作者gremo
相关产品推荐
相关产品推荐

