在看此文之前,建议先看前篇JavaScript设计模式之代理模式-实现加载图片loading
1.需求
假设有一个非常大的js文件,我们只在需要用的时候,才触发去加载它。比如有一个应用于移动端打印日志的控制台,在按F2才加载该文件并打印相关日志。效果如下:
2.实现
-
首先我们创建index.html文件,html代码如下:
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>虚拟代理惰性加载文件</title> <style> #consoleContent{ border:1px solid #ccc; width: 200px; height: 300px; color:#333; overflow: auto; display: none; } #consoleContent p{ margin: 0; padding: 5px 10px; vertical-align: middle; border-bottom:1px solid #ccc; overflow-wrap: break-word; } </style> </head> <body> <section id="consoleContent"></section> </body> </html>
-
接着在以上文件中插入script脚本,代码如下:
let miniConsole = (function () { let cache = []; // 当用户按下F2时,开始加载真正的miniConsole.js const handler = function (ev) { if (ev.keyCode === 113) { const script = document.createElement('script'); script.onload = function () { for (let i = 0, fn; fn = cache[i++];) { fn(); } cache = null; }; script.type = 'text/javascript'; script.src = "miniConsole.js"; document.getElementsByTagName('head')[0].appendChild(script); document.removeEventListener('keydown', handler); } }; document.addEventListener('keydown', handler, false); return { log: function () { const args = arguments; cache.push(function () { // 不直接用miniConsole.log(args)是为了解决传多个参数的问题 return miniConsole.log.apply(miniConsole,args); }) } } })(); miniConsole.log(11,22); miniConsole.log(22); miniConsole.log(33);
由于我们要加载的js文件中的对象为miniConsole,所以创建了一个同名代理对象:
- 在其中添加监听按键事件,当用户按下F2时,才开始加载真正的miniConsole.js文件;
- 实现与本体对应的log方法,文件未加载时,先存放于缓存对象cache中;
- 在真正的miniConsole.js加载完成后,调用cache中缓存的方法,实现真正的打印功能。
-
最后,miniConsole.js主要代码大致如下:
miniConsole = { log: function () { const p = document.createElement('p'); p.innerHTML = Array.prototype.join.call(arguments); const content = document.getElementById('consoleContent'); content.appendChild(p); content.style.display = 'block'; } };
3.思路总结
以上miniConsole.js有时候需要处理各种类型的日志打印,导致文件会更大。但我们这个功能不一定用户都会用,所以实现惰性加载,减少网络开销。
当我们遇到大文件且非必要的功能,我们可以用虚拟代理实现惰性加载,步骤如下:
- 创建与原文件接口相同的同名代理对象;
- 在特定需要的情况(如监听按键)时加载原文件;
- 在代理对象接口中缓存所有的调用,并监听文件加载,等文件加载完成时再进行执行。
代理模式系列:
注:参考书籍《JavaScript设计模式与开发实践》,喜欢可以关注博主哦,不断更新设计模式系列学习笔记~
不要吝啬点赞评论哦~