详解js异步文件加载器

我们经常会遇到这种场景,某些页面依赖第三方的插件,而这些插件比较大,不适合打包到页面的主js里(假设我们使用的是cmd的方式,js会打包成一个文件),那么这个时候我们通常会异步获取这些插件文件,并在下载完成后完成初始化的逻辑。

以图片上传为例,我们可能会用到plupload.js这个插件,那么我们会这么写:

!window.plupload ?
    $.getScript( "/assets/plupload/plupload.full.min.js", function() {
      self._initUploader();
    }) :
    self._initUploader();

但是我们的页面通常由多个独立的模块(组件)构成,如果页面上的A、B两个模块都依赖于plupload.js, 那是不是在两个地方都要把上面的代码写一遍。如果这么干,在plupload.js被下载下来之前,可能会发起两个请求,由于是并行下载,js文件可能会被重复下载,而不是第一次下载下来,第二次取缓存的内容。

下图是页面多个组件依赖vue.js的情况(jquery和vue混用的场景):

所以,在实际使用中需要加锁,即当脚本正在加载时,不应该再重复请求脚本,等待加载完成后,依次执行后面的逻辑,有promise这个好工具,实现起来很简单。

// 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;

然后在依赖vue.js地方:

loadvue().then(function() { // do something });

再看看请求:

好了,到这里似乎解决问题了,但是假如我的页面上存在多个插件依赖,比如既依赖plupload.js又依赖vue.js,难道我要把上面的代码再写一遍(怎么感觉好像说过这话)?这样不就冗余了么?所以我们需要一个异步加载器的生成器,能够帮助我们生成多个异步加载器。

/**
 * @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;
};

然后我们可以生成异步加载器并赋给window

// 全局加载器
window.loadvue = loader.generate(
'vue',
'Vue',
'/assets/vue/vue.min.js');
window.loadPlupload = loader.generate(
'plupload',
'plupload',
'/assets/plupload/plupload.full.min.js');

使用的时候同上,这样就基本解决了我们的问题。

以上就是关于js异步文件加载器的详细内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • 概述如何实现一个简单的浏览器端js模块加载器

    在es6之前,js不像其他语言自带成熟的模块化功能,页面只能靠插入一个个script标签来引入自己的或第三方的脚本,并且容易带来命名冲突的问题.js社区做了很多努力,在当时的运行环境中,实现"模块"的效果. 通用的js模块化标准有CommonJS与AMD,前者运用于node环境,后者在浏览器环境中由Require.js等实现.此外还有国内的开源项目Sea.js,遵循CMD规范.(目前随着es6的普及已经停止维护,不论是AMD还是CMD,都将是一段历史了) 浏览器端js加载器 实现一个简

  • JS加载器如何动态加载外部js文件

    今天在网上找到了一个可以动态加载js文件的js加载器,具体代码如下: JsLoader.js var MiniSite=new Object(); /** * 判断浏览器 */ MiniSite.Browser={ ie:/msie/.test(window.navigator.userAgent.toLowerCase()), moz:/gecko/.test(window.navigator.userAgent.toLowerCase()), opera:/opera/.test(windo

  • 浅析angularJS中的ui-router和ng-grid模块

    在家里闲着无聊,正好在网上找到了一个关于angular的教程,学习了一下angular的ui-router和ng-grid这两个模块,顺便模仿着做了一个小小的东西. 代码已经上传到github上,地址在这里哟https://github.com/wwervin72/Angular. 有兴趣的小伙伴可以看看.那么然后这里我们就先来了解一下这两个模块的用法. 我们先来说说ui-router这个模块,这个模块主要是用来实现深层次的路由的.其实angular有个内置的指令ng-route,如果在项目中没

  • AngularJS 模块化详解及实例代码

    AngularJS有几大特性,比如: 1 MVC 2 模块化 3 指令系统 4 双向数据绑定 那么本篇就来看看AngularJS的模块化. 首先先说一下为什么要实现模块化: 1 增加了模块的可重用性 2 通过定义模块,实现加载顺序的自定义 3 在单元测试中,不必加载所有的内容 之前做的几个例子,控制器的代码直接写在script标签里面,这样声明的函数都是全局的,显然不是一个最好的选择. 下面看看如何进行模块化: <script type="text/javascript">

  • 基于gulp合并压缩Seajs模块的方式说明

    之前的项目一直采用grunt来构建,然后用requirejs做模块化,requirejs官方有提供grunt的插件来做压缩合并.现在的项目切到了gulp,模块化用起了seajs,自然而然地也想到了模块合并压缩的问题. 然后一开始在解决这个问题的时候,并不是很顺利,在npm上并没有那种特别流行的专门用来做seajs合并压缩的gulp插件,虽然在seajs的github上也看了不少的issue,但是大多数都是只能将所有的模块文件合并成一个总的文件,这对于单页面的应用来说肯定没有问题,但是对于多页面的

  • 第二次聊一聊JS require.js模块化工具的基础知识

    前一篇:JS模块化工具我们以非常简单的方式引入了requirejs:http://www.jb51.net/article/82527.htm,这一篇将讲述一下requirejs中的一些基本知识,包括API使用方式等 基本API require会定义三个变量:define,require,requirejs,其中require === requirejs,一般使用require更简短 define 从名字就可以看出这个api是用来定义一个模块 require 加载依赖模块,并执行加载完后的回调函

  • 第一次接触JS require.js模块化工具

    随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求. RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的RequireJS压缩后只有14K,堪称非常轻量.它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升. requirejs能带来什么好处 官方对requ

  • 在Html中使用Requirejs进行模块化开发实例详解

    在前端模块化的时候,不仅仅是js需要进行模块化管理,html有时候也需要模块化管理.这里就介绍下如何通过requirejs,实现html代码的模块化开发. 如何使用requirejs加载html Reuqirejs有一个text的插件,它可以读取指定文件的内容,读取到的内容就是文本. 如何下载text插件 第一种方法,可以通过npm下载: npm install requirejs/text 第二种方法,也可以直接去官方github上面直接下载. 直接拷贝内容到text.js中即可. 如何安装t

  • Node.js中路径处理模块path详解

    前言 在node.js中,提供了一个path某块,在这个模块中,提供了许多使用的,可被用来处理与转换路径的方法与属性,将path的接口按照用途归类,仔细琢磨琢磨,也就没那么费解了.下面我们就来详细介绍下关于Node.js中的路径处理模块path. 获取路径/文件名/扩展名 获取路径:path.dirname(filepath) 获取文件名:path.basename(filepath) 获取扩展名:path.extname(filepath) 获取所在路径 例子如下: var path = re

  • AngularJs 动态加载模块和依赖

    最近项目比较忙额,白天要上班,晚上回来还需要做Angular知识点的ppt给同事,毕竟年底要辞职了,项目的后续开发还是需要有人接手的,所以就占用了晚上学习的时间.本来一直不打算写这些第三方插件的学习笔记,不过觉得按需加载模块并且成功使用这个确实是个好处,还是记录下来吧.基于本兽没怎么深入的使用requireJs,所以本兽不知道这个和requireJs有什么区别,也不能清晰的说明这到底算不算Angular的按需加载. 为了实现这篇学习笔记知识点的效果,我们需要用到: angular:https:/

  • seajs模块之间依赖的加载以及模块的执行

    本文介绍的是seajs模块之间依赖的加载以及模块的执行,下面话不多说直接来看详细的介绍. 入口方法 每个程序都有个入口方法,类似于c的main函数,seajs也不例外.系列一的demo在首页使用了seajs.use() ,这便是入口方法.入口方法可以接受2个参数,第一个参数为模块名称,第二个为回调函数.入口方法定义了一个新的模块,这个新定义的模块依赖入参提供的模块.然后设置新模块的回调函数,用以在loaded状态之后调用.该回调函数主要是执行所有依赖模块的工厂函数,最后在执行入口方法提供的回调.

  • 使用RequireJS库加载JavaScript模块的实例教程

    js通过script标签的默认加载方式是同步的,即第一个script标签内的js加载完成后,才开始加载第二个,以此类推,直至js文件全部加载完毕.且js的依赖关系必须通过script的顺序才能确保:而在js加载期间,浏览器将停止响应,这大大影响了用户体验,基于此,很多解决js以来和加载的方案出现,require js就是其中之一. requirejs加载的模块,一般为符合AMD标准的模块,即用define定义,用ruturn返回暴露方法.变量的模块:requirejs也可以加载飞AMD标准的模块

  • 浅析js的模块化编写 require.js

    requirejs是一个JavaScript文件和模块加载器.requireJS允许你把你的javascript代码独立成文件和模块,同时管理每个模块间的依赖关系. RequireJS的目标是鼓励代码的模块化,它使用了不同于传统"script"标签的脚本加载步骤.使用RequireJS加载模块化脚本将提高代码的加载速度和质量. 一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,

随机推荐