1

简介

说实话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>

强子
335 声望10 粉丝

尽人事,安天命!