简介
说实话 requireJS 我没应用过,起因是接触的 16 年时候感觉很鸡肋,随后马上就用 webpack ES6 模块化和 node 的 CommonJS 了,昨天看文章看到了模块化,就想着这个货色如何实现。想想的确也不是很简略。
简略实现,没看源码,也可能思路不是这样,无所谓了,就是练练手
思路
requireJS 的大略写法应该就是
require(['a', 'b'], function (a, b) {console.log(b + a)
})
和
define(['c'], function (c) {return 20 + c})
最根本的定义和应用就是这样了。
那么就开始剖析一下:
第一步:依据依赖项加载 js 文件;
既然要有依赖,那么必定要加载 js 文件,那么就要动静插入标签,插入标签很简略,那运行 callback 对应的参数变量怎么对应呢?
第二步:解决依赖项与 callback 运行时参数对应关系;
应用 requirejs 时候是 define 和 require 调用办法,这个时候引入 js 外面都是应用 define 来定义的。js 加载结束会触发 onload 事件,并且是与某个文件加载程序是一一对应的,那么能够在 onload 外面去运行 callback,至于 callback 须要的参数咱们能够定义一个变量去存储?
第三步:解决 callback 运行程序;
define 办法会依赖某些 js 文件,那么总有一个源头,会不依赖其余 js 文件,这个模型就像俄罗斯套娃,一个套一个,或者是洋葱,或者是大盒子套小盒子之类的;
把有依赖项的文件的 callback 放在一个数组外面先放着,等到他的依赖项都有了再去执行它,执行完了之后删除;
是的,就是在 onload 外面去执行。
这样是不是就能够了呢?当然还不行,还要解决 require 办法的 callback,依赖项曾经存在的状况,等等问题,这些问题都会影响加载后果。
上代码
a.js
define(['d'], function (d) {return 10 + d})
b.js
define(['c'], function (c) {return 20 + c})
c.js
define([], function () {return 20})
d.js
define([], function () {return 10})
require.js
(function () {const variables = {}
let moudle = null
const tasks = []
const createNode = function (depend) {let script = document.createElement("script");
script.src = `./${depend}.js`;
script.setAttribute("data-moduleName", depend);
let fs = document.getElementsByTagName('script')[0];
fs.parentNode.insertBefore(script, fs);
return script;
}
const hasAlldependencies = function (dependencies) {
let hasValue = true
dependencies.forEach(depd => {if (!variables.hasOwnProperty(depd)) {hasValue = false}
})
return hasValue
}
const implementCallback = function (callbacks) {if (callbacks.length) {callbacks.forEach((callback, index) => {if (hasAlldependencies(callback.dependencies)) {const returnValue = callback.callback(...callback.dependencies.map(it => variables[it]))
if (callback.name) {variables[callback.name] = returnValue
}
tasks.splice(index, 1)
implementCallback(tasks)
}
})
}
}
const require = function (dependencies, callback) {if (!dependencies.length) { // 这个文件没有依赖项
moudle = {value: callback()
}
} else { // 这个文件有依赖项
moudle = {
dependencies,
callback
}
tasks.push(moudle)
dependencies.forEach(function (item) {if (!variables[item]) {createNode(item).onload = function () {
let modulename = this.dataset.modulename
if (moudle.hasOwnProperty('value')) {variables[modulename] = moudle.value
} else {
moudle.name = modulename
if (hasAlldependencies(moudle.dependencies)) {variables[modulename] = el.callback(...moudle.dependencies.map(it => variables[it]))
}
}
implementCallback(tasks) // 递归执行 callback
}
}
})
}
}
window.require = require
window.define = require
})(window)
调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./require.js"></script>
<script>
require(['a', 'b'], function (a, b) {console.log(b + a)
})
</script>
</body>
</html>