We often encounter this scenario. Some pages rely on third-party plug-ins, and these plug-ins are relatively large. It is not suitable to be packaged into the main js of the page (assuming we are using the cmd method, the js will be packaged into a file), then at this time we usually obtain these plug-in files asynchronously and complete the initialization logic after the download is completed.
Taking image upload as an example, we may use the plupload.js plug-in, then we will write like this:
!window.plupload ? $.getScript( "/assets/plupload/plupload.full.min.js", function() { self._initUploader(); }) : self._initUploader();
But our pages are usually composed of multiple independent modules (components). If both modules A and B on the page depend on plupload.js, do we need to write the above code in both places? Again. If you do this, two requests may be initiated before plupload.js is downloaded. Since it is downloaded in parallel, the js file may be downloaded repeatedly instead of downloading it for the first time and fetching the cached content the second time.
The picture below shows the situation where multiple components of the page depend on vue.js (scenario where jquery and vue are mixed):
Therefore, locking is required in actual use, that is, when the script is loading, the script should not be requested repeatedly. After the loading is completed, the subsequent logic will be executed in sequence. With the good tool of promise, it is very simple to implement.
// vue加载器 var promiseStack = []; function loadvue() { var promise = $.Deferred(); if (loadvue.lock) { promiseStack.push(promise); } else { loadvue.lock = true; window.Vue ? promise.resolve() : // 这里写错了,window.Vue为true的时候lock要置为false,我在后面改过来了 $.getScript( "/assets/vue/vue.min.js", function() { loadvue.lock = false; promise.resolve(); promiseStack.forEach(function(prom) { prom.resolve(); }); }); } return promise; } window.loadvue = loadvue;
Then depend on vue.js:
loadvue().then(function() { // do something });
Look at the request again:
Okay, the problem seems to be solved here, but if there are multiple plug-in dependencies on my page, such as relying on both plupload.js and vue.js, do I have to write the above code again (how do I feel? seems to have said this)? Wouldn't this be redundant? So we need an asynchronous loader generator that can help us generate multiple asynchronous loaders.
/** * @des: js异步加载器生产器 * @param {string} name 加载器名称 * @param {string} global 全局变量 * @param {string} url 加载地址 **/ var promiseStack = {}; exports.generate = function(name, global, url) { var foo = function() { if (!promiseStack[name]) { promiseStack[name] = []; } var promise = $.Deferred(); if (foo.lock) { promiseStack[name].push(promise); } else { foo.lock = true; if (window[global]) { foo.lock = false; promise.resolve(); } else { $.getScript(url, function() { foo.lock = false; promise.resolve(); promiseStack[name].forEach(function(prom) { prom.resolve(); }); }); } } return promise; }; return foo; };
Then we can generate an asynchronous loader and assign it to window
// 全局加载器 window.loadvue = loader.generate( 'vue', 'Vue', '/assets/vue/vue.min.js'); window.loadPlupload = loader.generate( 'plupload', 'plupload', '/assets/plupload/plupload.full.min.js');
Use the same method as above, which basically solves our problem.
The above is the detailed content about the js asynchronous file loader. I hope it will be helpful to everyone's learning.