頁面多個獨立組件(如 A、B 兩個上傳模組)同時依賴大型第三方庫(如 plupload.js、vue.js)。若各自獨立發起請求,會造成重複下載、競態條件與資源浪費。
利用 jQuery $.Deferred() 與鎖機制,確保同一腳本只發一次請求:
var loadVue = (function() {
var lock = false;
var promiseStack = [];
return function() {
var deferred = $.Deferred();
if (lock) {
promiseStack.push(deferred);
} else {
lock = true;
if (window.Vue) {
lock = false;
deferred.resolve();
} else {
$.getScript('/assets/vue/vue.min.js', function() {
lock = false;
deferred.resolve();
promiseStack.forEach(function(p) { p.resolve(); });
promiseStack = [];
});
}
}
return deferred.promise();
};
})();
// 使用方式
loadVue().then(function() { /* Vue 已就緒 */ });
支援多種不同腳本,避免重複撰寫邏輯:
var Loader = (function() {
var promiseStacks = {};
function generate(name, globalVar, url) {
var loader = function() {
if (!promiseStacks[name]) promiseStacks[name] = [];
var deferred = $.Deferred();
if (loader.lock) {
promiseStacks[name].push(deferred);
} else {
loader.lock = true;
if (window[globalVar]) {
loader.lock = false;
deferred.resolve();
} else {
$.getScript(url, function() {
loader.lock = false;
deferred.resolve();
promiseStacks[name].forEach(function(p) { p.resolve(); });
promiseStacks[name] = [];
});
}
}
return deferred.promise();
};
return loader;
}
return { generate: generate };
})();
// 註冊全域載入器
window.loadVue = Loader.generate('vue', 'Vue', '/assets/vue/vue.min.js');
window.loadPlupload = Loader.generate('plupload', 'plupload', '/assets/plupload/plupload.full.min.js');
套用後,Network 面板顯示同一腳本僅請求一次,後續呼叫直接從快取或 Promise 解析取得,解決並發重複下載問題。
但在無法使用建置工具的舊專案中,上述 Promise 型載入器仍是輕量可靠的選擇。