资讯专栏INFORMATION COLUMN

模仿RequireJs的用法实现一个低配版的模块加载器

WalkerXu / 941人阅读

摘要:我想自己可以尝试一下写一个低配版的模块加载器来应付一下我这个单页网站,当然只是大致模仿了主要功能。是这样处理的模块依赖,同时依赖,这种情况下的模块函数被调用时,被传入的是,所以需要自己在里面手动一下。

Contents

前言

回顾RequireJs的基本用法

实现原理

使用方法

总结

前言

前段时间一直想用单页开发技术写一个自己的个人网站(使用es2015),写了一部分之后,发现单页应用因为只有一个页面,所以第一次加载index.html时就要下载所有js文件,并且为了好管理各个部分的状态,需要划分页面的各个功能区为各个模块,es2015本身是不支持一些模块规范的(比如AMD、CMD、CommonJs等),所以只能这样模拟实现:

  // global
  var spa = (function(){...})();

  // module blog
  spa.blog = (function(){
    ...
    return {
      do1: do1,
      do2: do2,
    };
  })();

  // module model
  spa.model = (function(){...})();

  // module shell
  spa.model = (function(){...})();

并且各个模块之间又存在一些依赖关系,在index.html里面写script标签来载入模块时需要写很多个,同时也要根据依赖关系来确定书写顺序,页面逻辑混乱,如下:

  
  
  
  
  
  
  

之前用过RequireJs(一个流行的JavaScript模块加载器),它是用同构js的架构来写的,所以node.js环境下也能使用。我想自己可以尝试一下写一个低配版的js模块加载器 requireJs-nojsja 来应付一下我这个单页网站,当然只是大致模仿了主要功能。

回顾RequireJs的基本用法 1. 配置模块信息
      requirejs.config({
          baseUrl: "/javascripts",  // 配置根目录
          paths: {
            moduleA: "a.js",
            moduleB: "b.js",
            moduleC: "c.js",
          },
          shim: {  // 配置不遵循amd规范的模块
            moduleC: {
              exports: "log",
              deps: ["moduleA"]
            }
          },
      });
2. 定义一个模块
  define(name, ["moduleA", "moduleB"], function(a, b){
    ...
    return {
      do: function() {
        a.doSomething();
        b.doAnother();
      }
    };
  });
3. 引用一个模块
  // 引用模块
  require(["moduleA", "moduleB"], function(a, b) {
    a.doSomething();
    b.doAnother();
  });
实现原理 1. config方法确定各个模块的依赖关系
  /* 记录模块访问地址和模块的依赖等信息 */
  Require.config({
    baseUrl: "/javascripts/",
    paths: {
      "moduleA": "./moduleA.js",  // 相对于当前目录
      "moduleB": "/javascripts/moduleB.js",  // 不使用baseUrl
      "moduleC": "moduleC.js",

      "moduleD": {
        url: "moduleD.js",
        deps: ["moduleE", "moduleF"],
      },
      ...
    },
    shim: {
      "moduleH": {
        url: "moduleH.js",
        exports: "log",
      },
    }
  });
2. 数据请求请求过程分析

(1) config配置模块信息时并不会触发网络请求
(2) 在index.js主入口文件里使用require方法引用多个模块时,根据config配置文件构造一下所有模块的依赖分析树。按深度优先或是广度优先来遍历这个依赖树,将所有依赖按照依赖顺序放进一个数组,最后进行数组去重处理,因为会出现依赖重复的情况

  var dependsTree = new Tree("dependsTree");
  var dependsArray = [];
  var dependsFlag = {};  // 解决循环依赖

  // 创建树
  setDepends(depends, dependsTree);
  // 得到依赖数组
  sortDepends(dependsArray, dependsTree);
  // 数据去重
  arrayFilter(dependsArray);

  return dependsArray;

(3) 创建XHR对象异步下载数组里面的所有js文件,按照依赖顺序挨个解析js代码,解析完成后触发回调函数,回调函数里传入各个模块的引用

  // ajax下载代码文件
  Utils.request(url, "get", null, function(responseText){
    // 暂时保存
    _temp[module_name] = responseText;
  });
    
  // 文件下载完成后eval解析代码
  array.map(function(jsText){
    ...
    eval(jsText);
    ...
  });
    
  // 调用回调函数
  callback.apply(null, [dep1, dep2, dep3]);
使用方法

详细说明: github README.md

总结

下载js代码时我用了ajax来实现,所以对于跨域文件和CDN会有点问题,这个可以改成创建script标签,指定标签src,最后将document.head.appendChild(script),这样来解决,其它的诸如使用XMLHttpRequest 2.0,iframe等也可以的,可以实验一下。

解析代码时我用了eval的方法,这个eval在JavaScript里面是众说纷纭,可以看看这个,如果是用了上面创建script标签的方法的话,就不用自己eval了。

发现一个bug,存在循环依赖时,代码会报错,还没去解决。RequireJs是这样处理的:模块a依赖b,同时b依赖a,这种情况下b的模块函数被调用时,被传入的a是undefined,所以需要自己在b里面手动require一下a。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92469.html

相关文章

  • 【教学向】再加150行代码教你实现一个配版web component库(1) —设计篇

    摘要:为的内置一个方法,用法和原生的事件机制一毛一样。 前言 上两篇Mvvm教程的热度超出我的预期,很多码友留言表扬同时希望我继续出下一篇教程,当时我也半开玩笑说只要点赞超10就兑现承诺,没想到还真破了10,所以就有了今天的文章。 准备工作 熟读 【教学向】150行代码教你实现一个低配版的MVVM库(1)- 原理篇【教学向】150行代码教你实现一个低配版的MVVM库(2)- 代码篇 本篇是在...

    Clect 评论0 收藏0
  • 【教学向】150行代码教你实现一个配版MVVM库(2)- 代码篇

    摘要:也放出地址,上面有完整工程以及在线演示地址相关阅读教学向行代码教你实现一个低配版的库原理篇教学向行代码教你实现一个低配版的库代码篇教学向再加行代码教你实现一个低配版的库设计篇教学向再加行代码教你实现一个低配版的库原理篇 书接上一篇: 150行代码教你实现一个低配版的MVVM库(1)- 原理篇 写在前面 为了便于分模块,和阅读,我使用了Typescript来进行coding,总行数是正好...

    loonggg 评论0 收藏0
  • 【教学向】150行代码教你实现一个配版MVVM库(1)- 原理篇

    摘要:模块则负责维护,以及各个模块间的调度思考题了解了的实现机制,你能否自己动手也试着用百来行代码实现一个库呢好了本教程第一部分设计篇就写到这里,具体请移步下一篇教学向行代码教你实现一个低配版的库代码篇我会用给出一版实现。 适读人群 本文适合对MVVM有一定了解(如有主流框架ng,vue等使用经验配合本文服用则效果更佳),虽然会用这类框架,但是对框架底层核心实现又不太清楚,或者能说出个所以然...

    selfimpr 评论0 收藏0
  • 基于canvas和web audio实现配版MikuTap

    摘要:导言最近发掘了一个特别的网页小游戏。于是第二天我就继续沉迷,随着一阵抽搐,这个游戏索然无味之后,冷静的我决定用和开发出一个低配版。我的低配版在交互操作比较高的情况下,还是比较卡的,没有原网页的流畅性,可能后续考虑版本实现。 导言 最近发掘了一个特别happy的网页小游戏--MikuTap。打开之后沉迷了一下午,导致开发工作没做完差点就要删库跑路了,还好boss瞥了我一眼就没下文了。于是...

    Awbeci 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<