script 标签的两个参数, - async & defer
总结: 普通: - 解析到标签, 立刻pending, 并且下载同时执行 defer
- 解析到标签, 开始异步下载, 继续往后进行完成之后开始执行
async
-
解析到标签, 开始异步下载, 下载完成之后立刻执行且阻塞继续往后解析, 执行完成之后再继续向下
问题:
- 污染全局作用域
模块化雏形 - IIFE
作用域的把控
定义函数 + 立即执行 => 独立空间
尝试定义一个简单的模块
const module = (() => {
let count = 0
return {
increase: () => ++count;
reset: () => {
count = 0
}
}
})()
module.increase()
module.reset()
// 有外部依赖的情况下,如何优化处理
const iifeModule = ((dependencyModule1, dependencyModule2) => {
let count = 0
return {
increase: () => ++count;
reset: () => {
count = 0
}
}
})(dependencyModule1, dependencyModule2)
// 掲示模式
const iifeModule = ((dependencyModule1, dependencyModule2) => {
let count = 0
const increase = () => ++count
const reset = () => {
count = 0
}
return {
increase,
reset
}
})(dependencyModule1, dependencyModule2)
面试方向
-
- 深入模块化实现
-
- 转向框架,jquery vue react 模块化组件实现细节, 以及框架原理特征
-
- 转向设计模式, - 注重模块化设计
成熟期
CJS - commonsjs
node.js 制定的标准 特征
- 通过module + export 去对外暴露接口
- 通过require 去调用其他模块
模块的组织方式 dep.js
// 引入部分
const dependencyModule1 = require(../dependencyModule1)
const dependencyModule2 = require(../dependencyModule1=2)
let count = 0
const increase = () => ++count
const reset = () => {
count = 0
}
// 暴露接口部分
export.increase = increase
export reset = reset
module.exports = {
increase,
reset
}
const {increse, reset } = require('dep.js')
increase()
reset()
优点
- CJS服务侧的角度解决了依赖全局污染的问题 + 完完全全地在写法上也实现了主观感受的模块化
缺点:
- 针对服务端 => 异步
AMD
通过异步加载 + 允许定制回调函数
经典的实现框架: require.js
新增定义方式
// 通过define来定义一个模块, 然后再用require去加载
define(id, [depends], callback)
require([module], callback)
define('amdModule', ['dependencymodule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => {
let count = 0
const increase = () => ++count
const reset = () => {
count = 0
}
})
require(['amdModule'], amdModule => {
amdModule.increase()
})
** 面试题
define('amdModule', [], require => {
const dependencyModule1 = require(./dependencyModule1)
const dependencyModule2 = require(./dependencyModule2)
})
面试: 区分CJS和AMD? 手写兼容AMD& CJS的模块 // UMD
define('amdModule', ['dependencymodule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => {
let count = 0
const increase = () => ++count
const reset = () => {
count = 0
}
})(
// 目标:一次去定位区分CJS和AMD
// 1.CJS factory
// 2. module module.export
// define
typeof module === 'Object'
&& module.exports
&& typeof define !== 'function'
? // 是CJS
factory=> module.exports=> factory(require, exports, module)
: // 是AMD
define
)
优点:
- 解决了服务 , 客户端异步动态依赖的问题
缺点:
- 会有引入成本, 没有考虑按需加载
CMD规范
按需加载
主要应用框架 sea.js
依赖就近
define('moudle', (require, export, module) => {
let $ = require('map')
// 代码快
if(xxx){
return
}
let depend2 = require(./dependencyModule2)
// 代码快2
})
优点:
- 按需加载,依赖就近
缺点:
- 依赖打包
- 扩大模块内的体积
完全体 ESM
新增定义 引入: import 导出: export
import dependencyModule1 from './dependencyModule1'
// ...
export default{
increase,
reset
}
面试:
-
- 处理动态一步依赖
// es方式
const moduleDependency = async() => {
return await dependencyModule1.init()
}
// 原生
import('./dependencyModule.js').then(dynamicEsmodule => {
dynamicEsmodule.init()
})
优点:
- 通过最统一的形态整合了所有的js模块化
函数式编程
const fetch = ajax(method, url, params)
const fetch = ajax.get(url)
const request = fetch(params)
const fetch = ajax(method)(url)(params)
send(request, fetch)
// 科里化