2.SMD(同步模块模式)

2019-10-17  本文已影响0人  zdxhxh

前端模块的进化史

作为刚入门的前端开发人员,并不了解曾经的前端是如何进行开发的,更是在脚手架满天飞的现实中,对webpack打包,垫片等存在质疑,为什么打包成一个bundle.js就是合理的呢?import ('')与import '' 的区别在哪里?webpack是如何实现的?browersiry

阶段一:全局函数模式

function a() {}
function b() {} 
function c() {} 
function ...

阶段二:单例封装模式

let obj = { 
  msg2 : 'module2',
  foo() { 
    console.log('xxxx)
  }
}

阶段三 : 匿名闭包: IIFE模式

var module = (function(){
  var a = 'name'
  return { 
    return a 
  }
}())

阶段四 : 依赖引入

var module = (function($){
  var Dom = { 
    a : $('#a')
  }
  return Dom
}(jQuery))

SMD(Synchronous Module Definition)

曾经的前端人员似乎有这样的困惑

// A工程师(创建导航)
var createNav = function() { 
  ...
  // B工程师(给导航添加引导图片)
  ...
  // C工程师(对导航增加事件处理)

}


首先要吐槽的是 : 
- 一个导航分三个人做,人员分配极其不科学
- 如果A永远的停留在创建导航过程,后面的人是不是要排队

为此,需要模块化的开发,即接口

``html
<script src="./A.js">
<script src="./B.js">
<script src="./C.js">

在A.js中

// IIFE
(function moduleA(window){
  // 挂载到window对象中
  window.moduleA = { 
    nav : document.getElementById('nav')
  }
}(window))

然后,模块B也是通过window直接引用A暴露的接口

优缺点 :

但是对于window对象来说,挂载到浏览器的原生对象上,也不是一个好的选择。

简单实现SMD

就是说,我想要实现以下数据结构,并用如下方法定义。

var modules = { 
  // a模块
  a : { 
    name : 'aaaa'
  },
  b : { 
    name : 'cccccc'
  }
}

F.defined('a.name',function(){ 
  return 'aaaaa'
})

模块定义

var F = (function () {
  // 模块缓存
  var modules = {}
  // 定义模块方法
  var define = function (str, fn) {
    var parts = str.split('.'),
      pre,
      current = modules
    // 遍历路由模块
    for (var i = 0; i < parts.length; i++) {
      // 如果不存在当前模块,则声明当前模块
      if (typeof current[parts[i]] === 'undefined') {
        current[parts[i]] = {}
      }
      // 缓存上一级模块
      pre = current
      // 矫正当前模块
      current = current[parts[i]]
    }
    if (fn) {
      pre[parts[i - 1]] = fn()
    }
    // 打印当前模块
    console.log(modules)
  }
  return {
    define
  }
}())

测试一下该方法

F.define('a.name', function () {
  return 'aaaaaaa'
})
F.define('b.name', function () {
  return 'bbbbbb'
})

打印成功


模块调用

对于模块的调用方法,参数分为两个部分,依赖模块与回调执行模块。如

F.module(['a','b'],function(a,b) { 
  console.log(a.name,b.name)
})
var module = function (depNames, callback) {
  // 依赖模块名,统一作数组处理
  var modNames = depNames instanceof Array ? depNames : [depNames],
    deps = []
  // 遍历模块
  modNames.forEach(function (modName) {
    var parts = modName.split('.'),
      temp = modules
    for (var i = 0; i < parts.length; i++) {
      if (temp[parts[i]]) {
        temp = temp[parts[i]]
      } else {
        console.log("Warnning : " + modName + 'not found')
        return deps.push(undefined)
      }
    }
    deps.push(temp)
  })
  callback && callback.apply(null, deps)
  console.log('打印模块调用依赖', deps)
}

测试

F.module(['a', 'b'], function (a, b) {
  console.log("回调了", a.name, b.name)
})

本章小结

模块化开发实际上是分治的思想,对系统功能进行分解,是系统随着功能增加而变得可控可维护。

实现模块化往往创建了大量的闭包,这会在内存中占用大量的资源。

但是,这种模式的最大缺点是,script标签必须依次加载,顺序不能乱,才能顺利进行。这对性能弱鸡的浏览器来讲,这是最大的痛点。

上一篇 下一篇

猜你喜欢

热点阅读