实现简单的 JS 模块加载器

实现简单的 JS 模块加载器

按需加载是前端性能优化的一个重要手段,按需加载的本质是从远程服务器加载一段JS代码(这里主要讨论JS,CSS或者其他资源大同小异),该JS代码就是一个模块的定义,如果您之前有去思考过按需加载的原理,那你可能已经知道按需加载需要依赖一个模块加载器。它可以加载所有的静态资源文件,比如:

  • JS 脚本
  • CSS? 脚本
  • 图片 资源

如果你了解 webpack,那您可以发现在 webpack 内部,它实现了一个模块加载器。模块加载器本身需要遵循一个规范,当然您可以自定义规范,大部分运行在浏览器模块加载器都遵循 AMD 规范,也就是异步加载。

下面是一个基于AMD规范的简单的模块加载器:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  1. 相同模块的并发加载问题?
</body>
<script>
  // 模块加载配置
  var config = {
    baseDir: window.location.origin + '/module'
  }

  // loader 模块加载器
  var loader = {
    // 配置
    config: {
      baseDir: window.location.origin + '/module'
    },

    // 缓存
    modules: {},

    // 注册加载后的回调
    installed: {},

    // 标记某个模块是否已经加载
    status: {},

    // 定义模块
    define: function(name, fn) {
      this.modules[name] = fn ? fn() : undefined
    },

    // 加载模块
    require: function(name, fn) {
      if (this.modules[name]) {
        // 已经加载成功, 直接从缓存读取
        callback(this.modules[name])
      } else {
        if (this.status[name]) {
          // 加载过了, 但是还未加载成功
          this.installed[name].push(fn)
        } else {
          // 还未加载过
          this.installed[name] = []
          this.installed[name].push(fn)
          this.loadScript(name)
          this.status[name] = true
        }
      }
    },

    // 加载JS文件
    loadScript: function (name, callback) {
      let _this = this
      let script = document.createElement('script')

      script.src = this.config.baseDir + '/' + name + '.js'
      script.onload = function () {
        _this.installed[name].forEach(fn => fn(_this.modules[name]))
      }
      setTimeout(() => {
        // 模拟请求时间
        document.body.append(script)
      }, 200)
    }
  }

  loader.require('lazyload', function(lazyload){
    console.log(Date.now())
    lazyload()
  })

  loader.require('lazyload', function(lazyload){
    console.log(Date.now())
    lazyload()
  })

  loader.require('moment', function(moment){
    console.log(moment)
  })
</script>
</html>

主要的相关点在于:

  • 模块的定义方法
  • 模块的加载方法
  • 已经加载过的模块需要缓存
  • 同一个模块并行加载的处理

还未考虑的点包括:

  • 模块加载失败时异常处理
  • 定义模块时,该模块依赖其他模块
  • ......

可以看出的是,对于某个应用使用了模块加载器,那么首先需要加载该JS代码,然后有一个主模块,程序从主模块开始执行, requireJS 中使用main来标记,webpack 中叫?webpackBootstrap 模块。

以上代码有助于帮您理解 requireJS 和 webpack 应用的运行流程。

原文地址:https://www.cnblogs.com/gaollard/p/12227997.html

时间: 2024-10-03 21:53:34

实现简单的 JS 模块加载器的相关文章

js模块化/js模块加载器/js模块打包器

之前对这几个概念一直记得很模糊,也无法用自己的语言表达出来,今天看了大神的文章,尝试根据自己的理解总结一下,算是一篇读后感. 大神的文章:http://www.css88.com/archives/7628(大神的文章写的很详细,建议先看完大神的文章) 一.js模块化 什么是js模块化,我们从历史说起. 1.一开始我们怎么写脚本?就是在html文件中用<script></script>写代码 这种方式的缺点:代码复用靠复制,基本是全局变量. 2.后来我们用js文件写代码,用<

JS模块加载器加载原理是怎么样的?

路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的对应原则,加载器才能知道需要加载的 js 的路径.在这个例子里,就是 baseUrl + 'a.js' 和 baseUrl + 'b.js'. 但 id 和 path 的对应关系并不是永远那么简单,比如在 AMD 规范里就可以通过配置 Paths 来给特定的 id 指配 path. 原理二:crea

关于前端JS模块加载器实现的一些细节

最近工作需要,实现一个特定环境的模块加载方案,实现过程中有一些技术细节不解,便参考 了一些项目的api设计约定与实现,记录下来备忘. 本文不探讨为什么实现模块化,以及模块化相关的规范,直接考虑一些技术实现原理. 1.简单实现模块化 一开始我想如果我的代码只有一个文件,那几行不就实现了吗 main.js var modules = {} var define = function(id,factory){ moudles[id] = factory } var require = function

模块加载器

模块加载器 最近在做新项目的时候自己利用一点业余时间写了一个简单的js模块加载器.后来因为用了webpack就没有考虑把它放到项目里面去,也没有继续更新它了.模块加载器开源的有很多,一般来说seaJS和reqiureJS都能满足基本需求.本篇博文主要分享一下卤煮写这个加载器的一些想法和思路,作为学习的记录. js模块化加载已经不是一个新鲜概念了,很多人都一再强调,大型项目要使用模块化开发,因为一旦随着项目的增大,管理和组织代码的难度会越来越难,使得我们对代码的管理变得重要起来.当然,在后端模块化

【模块化编程】理解requireJS-实现一个简单的模块加载器

在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ...... 为了深入了解加载器,中间阅读过一点requireJS的源码,但对于很多同学来说,对加载器的实现依旧不太清楚 事实上不通过代码实现,单单凭阅读想理解一个库或者框架只能达到一知半解的地步,所以今天便来实现一个简单的加载器 加载器原理分析 分与合 事实上,一个程序运行需要完整的模块,以下代码为例: 1

自研模块加载器(三) module模块构造器设计-模块数据初始化

依赖加载策略 模块数据初始化 status状态生命周期 代码展示 demo包括4个文件, index.html , a.js , b.js , startUp.js index.html <!DOCTYPE html> <html> <head> <title>自研模块加载器</title> </head> <body> <script src="./startUp.js"></scr

Sea.js 是一个模块加载器

1 模块定义define define(function(require,exports,module){ //require 引入需要的模块如jquery等 //var $ = require('./jquery'); //exports可以把方法或属性暴露给外部 exports.name = 'hi'; exports.hi = function(){ alert('hello'); } //module提供了模块信息 }); 2 使用定义好的模块seajs.use <!doctype ht

JavaScript AMD 模块加载器原理与实现

关于前端模块化,玉伯在其博文 前端模块化开发的价值 中有论述,有兴趣的同学可以去阅读一下. 1. 模块加载器 模块加载器目前比较流行的有 Requirejs 和 Seajs.前者遵循 AMD规范,后者遵循 CMD规范.前者的规范产出比较适合于浏览器异步环境的习惯,后者的规范产出对于写过 nodejs 的同学来说是比较爽的.关于两者的比较,有兴趣的同学请参看玉伯在知乎的回答 AMD和CMD的区别有哪些.本文希望能按照 AMD 规范来简单实现自己的一个模块加载器,以此来搞清楚模块加载器的工作原理.

require.js模块加载js

RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的RequireJS压缩后只有14K,堪称非常轻量.它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升. requirejs能带来什么好处 官方对requirejs的描述: RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it