Maison > Article > interface Web > Introduction détaillée à la modularisation JavaScript et à l'analyse du code source SeaJs
La structure des pages Web devient de plus en plus complexe. Elle peut être considérée comme une simple application. Si vous mettez toujours tout le code dans un seul fichier comme avant, il y aura quelques problèmes : <.>
Principe de base
var module1 = new Object({ _count : 0, m1 : function (){ //... }, m2 : function (){ //... } });Chacun peut définir des modules de différentes manières s'ils peuvent tous suivre certaines. cahier des charges, L'avantage serait énorme : vous pourrez vous référencer !
var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })();
Spécification du module
function add(a, b){ return a + b; } exports.add = add;Il n'y a aucun problème de synchronisation avec require sur le serveur, mais le navigateur ne peut pas le faire dans un environnement réseau, il existe donc une spécification AMD asynchrone :
var math = require('math'); math.add(2,3);module La définition est la suivante (les modules peuvent dépendre d'autres modules) :
require(['math'], function (math) {// require([module], callback); math.add(2, 3); });Vous pouvez charger bien d'autres ressources avec RequireJS (voir ici), qui est très bon et puissant ! J'utilise SeaJS plus souvent au travail, et la spécification utilisée s'appelle CMD. Elle est recommandée (doit faire référence au mode asynchrone) :
define(function (){ // define([module], callback); var add = function (x,y){ return x+y; }; return { add: add }; });aussi paresseux que possible !
La différence entre la méthode de traitement des modules dépendants et AMD est :AMD est exécuté à l'avance (les dépendances sont devant), et CMD est exécuté en différé manière (les dépendances sont à proximité).
La façon de définir un module dans CMD est la suivante :Pour l'utilisation, veuillez vous référer directement au document, je n'entrerai donc pas dans les détails ici !
define(function(require, exports, module) { var a = require('./a'); a.doSomething(); var b = require('./b'); b.doSomething(); });
Analyse du code source SeaJS
C’est effectivement le cas, mais pas entièrement ! Commençons par regarder le code SeaJS (sea-debug.js). Un module peut passer par les états suivants pendant le processus de chargement :L'objet
var STATUS = Module.STATUS = { // 1 - The `module.uri` is being fetched FETCHING: 1, // 2 - The meta data has been saved to cachedMods SAVED: 2, // 3 - The `module.dependencies` are being loaded LOADING: 3, // 4 - The module are ready to execute LOADED: 4, // 5 - The module is being executed EXECUTING: 5, // 6 - The `module.exports` is available EXECUTED: 6, // 7 - 404 ERROR: 7 }est utilisé en mémoire pour conserver les informations du module :
Modul
function Module(uri, deps) { this.uri = uri this.dependencies = deps || [] // 依赖模块ID列表 this.deps = {} // 依赖模块Module对象列表 this.status = 0 // 状态 this._entry = [] // 在模块加载完成之后需要调用callback的模块 }:
seajs.use
seajs.use(‘./main’, function(main) {// 依赖及回调方法 main.init(); });:
Module.prototype.load
Module.prototype.load = function() { var mod = this if (mod.status >= STATUS.LOADING) { return } mod.status = STATUS.LOADING var uris = mod.resolve() // 解析依赖模块的URL地址 emit("load", uris) for (var i = 0, len = uris.length; i < len; i++) { mod.deps[mod.dependencies[i]] = Module.get(uris[i])// 从缓存取或创建 } mod.pass(); // 将entry传递给依赖的但还没加载的模块 if (mod._entry.length) {// 本模块加载完成 mod.onload() return } var requestCache = {}; var m; // 加载依赖的模块 for (i = 0; i < len; i++) { m = cachedMods[uris[i]] if (m.status < STATUS.FETCHING) { m.fetch(requestCache) } else if (m.status === STATUS.SAVED) { m.load() } } for (var requestUri in requestCache) { if (requestCache.hasOwnProperty(requestUri)) { requestCache[requestUri]() } } }. Je n'ai pas trouvé d'article facile à comprendre sur Internet, alors j'ai regardé le code et je l'ai deviné, et je l'ai à peu près compris. En fait, rappelez-vous simplement son objectif :
_entry
En d'autres termes :Le array_entry stocke une liste des dépendances de module qui peuvent être chargées après le chargement du module actuel (relation inverse des dépendances) !
Par exemple, si le module A dépend des modules B, C et D, alors le statut après réussite est le suivant :
À cette fois A Le
in est 3, ce qui signifie qu'il a encore trois modules dépendants qui n'ont pas été chargés ! Et si le module B dépend des modules E et F, alors A sera également distribué lors de son chargement :remain
Il y a plusieurs détails :
Module.prototype.fetch
sendRequest
sera exécutée : load
error
onload
où
Module.prototype.onload = function() { var mod = this mod.status = STATUS.LOADED for (var i = 0, len = (mod._entry || []).length; i < len; i++) { var entry = mod._entry[i] if (--entry.remain === 0) { entry.callback() } } delete mod._entry }signifie que tous les modules dont il dépend ont été chargés ! Ensuite, la fonction de rappel sera exécutée à ce moment :
--entry.remain
entry.remain === 0
Une fois le script téléchargé, la méthode
for (var i = 0, len = uris.length; i < len; i++) { exports[i] = cachedMods[uris[i]].exec(); } if (callback) { callback.apply(global, exports)// 执行回调函数 }
define
Lorsque les dépendances ne sont pas explicitement spécifiées, ParseDependencies sera utilisé pour utiliser le fragment require() dans la méthode de correspondance régulière (c'est une bonne pratique de spécifier une liste de dépendances).
Exécutez ensuite la méthode
pour générer les données du module :
var exports = isFunction(factory) ? factory.call(mod.exports = {}, require, mod.exports, mod) : factory
然后执行你在seajs.use中定义的callback
方法:
if (callback) { callback.apply(global, exports) }
当你写的模块代码中require时,每次都会执行factory方法:
function require(id) { var m = mod.deps[id] || Module.get(require.resolve(id)) if (m.status == STATUS.ERROR) { throw new Error('module was broken: ' + m.uri) } return m.exec() }
到这里核心的逻辑基本上讲完了,补一张状态的转换图:
以后在用的时候就可以解释一些诡异的问题了!
模块化非常好用,因此在ECMAScript 6中也开始支持,但是浏览器支持还是比较堪忧的~~
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!