Heim  >  Artikel  >  php教程  >  Laden von Abhängigkeiten zwischen SeaJS-Modulen und Ausführung von Modulen

Laden von Abhängigkeiten zwischen SeaJS-Modulen und Ausführung von Modulen

高洛峰
高洛峰Original
2016-12-28 13:55:151465Durchsuche

In diesem Artikel wird das Laden von Abhängigkeiten zwischen Seajs-Modulen und die Ausführung von Modulen vorgestellt. Wir gehen im Folgenden nicht auf Details ein.

Eingabemethode

Jedes Programm verfügt über eine Eingabemethode, ähnlich der Hauptfunktion von c, und Seajs ist keine Ausnahme. Die Demo der Serie 1 verwendet seajs.use() auf der Homepage, die Eingabemethode. Die Eingabemethode kann zwei Parameter akzeptieren, der erste Parameter ist der Modulname und der zweite Parameter ist die Rückruffunktion. Die Eingabemethode definiert ein neues Modul, und dieses neu definierte Modul hängt von dem Modul ab, das durch den Eingabeparameter bereitgestellt wird. Stellen Sie dann die Rückruffunktion des neuen Moduls so ein, dass sie nach dem Ladezustand aufgerufen wird. Diese Rückruffunktion führt hauptsächlich die Factory-Funktionen aller abhängigen Module aus und führt schließlich den von der Eingabemethode bereitgestellten Rückruf aus.

// Public API
// 入口地址
seajs.use = function(ids, callback) {
 Module.preload(function() {
 Module.use(ids, callback, data.cwd + "_use_" + cid())
 })
 return seajs
}
 
// Load preload modules before all other modules
Module.preload = function(callback) {
 var preloadMods = data.preload
 var len = preloadMods.length
 
 if (len) {
 Module.use(preloadMods, function() {
  // Remove the loaded preload modules
  preloadMods.splice(0, len)
 
  // Allow preload modules to add new preload modules
  Module.preload(callback)
 }, data.cwd + "_preload_" + cid())
 }
 else {
 callback()
 }
}
 
// Use function is equal to load a anonymous module
Module.use = function (ids, callback, uri) {
 var mod = Module.get(uri, isArray(ids) ? ids : [ids])
 
 mod.callback = function() {
 var exports = []
 var uris = mod.resolve()
 
 for (var i = 0, len = uris.length; i < len; i++) {
  exports[i] = cachedMods[uris[i]].exec()
 }
 // 回调函数的入参对应依赖模块的返回值
 if (callback) {
  callback.apply(global, exports)
 }
 
 delete mod.callback
 }
 
 mod.load()
}

Module.preload wird zum Vorladen der von Seajs bereitgestellten Plug-Ins verwendet. Es handelt sich nicht um eine Hauptfunktion und kann ignoriert werden. Module.use ist die Kernmethode. Wie bereits erwähnt, erstellt diese Methode ein neues Modul, legt die Rückruffunktion fest und lädt schließlich alle abhängigen Module des neuen Moduls.

Die Lademethode zum Laden von Abhängigkeiten

Die Lademethode kann als die Essenz von Seajs bezeichnet werden. Diese Methode lädt hauptsächlich die abhängigen Module und führt die Rückruffunktionen der abhängigen Module nacheinander aus. Die letzte Rückruffunktion ist der Rückruf des neuen Moduls, das über seajs.use("./name") erstellt wurde, nämlich mod.callback.

Die Lademethode lädt abhängige Module rekursiv. Wenn das abhängige Modul auch von anderen Modulen abhängt, laden Sie dieses Modul. Dies wird durch _waitings und _remain in der Module-Klasse erreicht.

Module.prototype.load = function() {
 var mod = this
 
 // If the module is being loaded, just wait it onload call
 if (mod.status >= STATUS.LOADING) {
 return
 }
 
 mod.status = STATUS.LOADING
 
 // Emit `load` event for plugins such as combo plugin
 var uris = mod.resolve()
 emit("load", uris, mod)
 
 var len = mod._remain = uris.length
 var m
 
 // Initialize modules and register waitings
 for (var i = 0; i < len; i++) {
 m = Module.get(uris[i])
 
 // 修改 依赖文件 的 _waiting属性
 if (m.status < STATUS.LOADED) {
  // Maybe duplicate: When module has dupliate dependency, it should be it&#39;s count, not 1
  m._waitings[mod.uri] = (m._waitings[mod.uri] || 0) + 1
 }
 else {
  mod._remain--
 }
 }
 
 // 加载完依赖,执行模块
 if (mod._remain === 0) {
 mod.onload()
 return
 }
 
 // Begin parallel loading
 var requestCache = {}
 
 for (i = 0; i < len; i++) {
 m = cachedMods[uris[i]]
 
 // 该依赖并未加载,则先fetch,将seajs.request函数绑定在对应的requestCache上,此时并未加载模块
 if (m.status < STATUS.FETCHING) {
  m.fetch(requestCache)
 }
 else if (m.status === STATUS.SAVED) {
  m.load()
 }
 }
 
 // Send all requests at last to avoid cache bug in IE6-9. Issues#808
 // 加载所有模块
 for (var requestUri in requestCache) {
 if (requestCache.hasOwnProperty(requestUri)) {
  // 此时加载模块
  requestCache[requestUri]()
 }
 }
}
 
// 依赖模块加载完毕执行回调函数
// 并检查依赖该模块的其他模块是否可以执行
Module.prototype.onload = function() {
 var mod = this
 mod.status = STATUS.LOADED
 
 if (mod.callback) {
 mod.callback()
 }
 console.log(mod)
 // Notify waiting modules to fire onload
 var waitings = mod._waitings
 var uri, m
 
 for (uri in waitings) {
 if (waitings.hasOwnProperty(uri)) {
  m = cachedMods[uri]
  m._remain -= waitings[uri]
  if (m._remain === 0) {
  m.onload()
  }
 }
 }
 
 // Reduce memory taken
 delete mod._waitings
 delete mod._remain
}

Initialisieren Sie zunächst die Attribute _waitings und _remain des Moduls. Wenn _remain 0 ist, bedeutet dies, dass keine Abhängigkeit vorhanden ist oder die Abhängigkeit geladen ist. Wenn sie nicht 0 ist, kann die Onload-Funktion ausgeführt werden , fetch ist nicht geladen. Hier gibt es einen kleinen Implementierungstrick, der darin besteht, alle Abhängigkeiten gleichzeitig zu laden: Das RequestCache-Objekt speichert die Ladefunktion: (definiert in der Abruffunktion)

if (!emitData.requested) {
 requestCache ?
  requestCache[emitData.requestUri] = sendRequest :
  sendRequest()
 }

Darunter ist die sendRequest-Funktion definiert wie folgt:

function sendRequest() {
 seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)
 }

Alle Abhängigkeiten parallel laden. Wenn die Abhängigkeiten geladen sind, wird der onRequest-Rückruf ausgeführt, sprudelt hervor und lädt die abhängigen Abhängigkeiten, bis keine abhängigen Module mehr vorhanden sind.

Wenn die Abhängigkeit der obersten Ebene nicht mehr vom Modul abhängt, führen Sie die Onload-Funktion aus, setzen Sie den Status im Funktionskörper auf „geladen“, führen Sie mod.callback aus und überprüfen Sie das _waitings-Attribut des Moduls und setzen Sie es auf Bestimmen Sie, ob das untere Modul noch vorhanden ist. Wenn nicht, wird der mod.callback des unteren Moduls ausgeführt. Diese Backtracking-Sequenz führt schließlich den mod.callback des über seajs.use erstellten anonymen Moduls aus.

Beispiel

Verwenden Sie ein einfaches Beispiel, um den obigen Prozess zu demonstrieren:

tst.html
 
<script>
  seajs.use(&#39;./b&#39;);
</script>
-------------------------------------
a.js
 
define(function(require,exports,module){
 exports.add = function(a,b){
  return a+b;
 }
})
------------------------------------
b.js
 
define(function(require,exports,module){
 var a = require("./a");
 console.log(a.add(3,5));
})

Mit Debugging-Tools können Sie die Reihenfolge sehen, in der onload ausgeführt wird:

Laden von Abhängigkeiten zwischen SeaJS-Modulen und Ausführung von Modulen

Schließlich ist ersichtlich, dass der Statuscode des anonymen Moduls 4 ist, was bedeutet, dass das Modul nicht ausgeführt wurde. Tatsächlich ist für das anonyme Modul keine Factory-Funktion definiert Modul und es kann nicht ausgeführt werden.

Modulausführung exec

Die Modulausführung wird im in seajs.use definierten mod.callback aufgerufen, und alle abhängigen exec-Methoden werden nacheinander aufgerufen, um das Programm auszuführen Logik. Die exec-Methode enthält einige wichtige Schlüsselwörter oder Funktionen von commonJS, z. B. require, exports usw. Werfen wir einen Blick darauf:

Module.prototype.exec = function () {
 var mod = this
 
 // When module is executed, DO NOT execute it again. When module
 // is being executed, just return `module.exports` too, for avoiding
 // circularly calling
 if (mod.status >= STATUS.EXECUTING) {
 return mod.exports
 }
 
 mod.status = STATUS.EXECUTING
 
 // Create require
 var uri = mod.uri
 
 function require(id) {
 return Module.get(require.resolve(id)).exec()
 }
 
 require.resolve = function(id) {
 return Module.resolve(id, uri)
 }
 
 require.async = function(ids, callback) {
 Module.use(ids, callback, uri + "_async_" + cid())
 return require
 }
 
 // Exec factory
 var factory = mod.factory
 
 // 工厂函数有返回值,则返回;
 // 无返回值,则返回mod.exports
 var exports = isFunction(factory) ?
  factory(require, mod.exports = {}, mod) :
  factory
 
 if (exports === undefined) {
 exports = mod.exports
 }
 
 // Reduce memory leak
 delete mod.factory
 
 mod.exports = exports
 mod.status = STATUS.EXECUTED
 
 // Emit `exec` event
 emit("exec", mod)
 
 return exports
}

Die Funktion require ruft das Modul ab und führt die Factory-Funktion des Moduls aus den Rückgabewert erhalten. Die Auflösungsmethode der Anforderungsfunktion ruft die absolute URL des entsprechenden Modulnamens ab, und die asynchrone Methode der Anforderungsfunktion lädt Abhängigkeiten asynchron und führt Rückrufe aus. Für den Rückgabewert der Factory-Methode gilt: Wenn die Factory-Methode ein Objekt ist, ist dies der Wert von exports. Wenn die Factory-Methode einen Rückgabewert hat, ist dies der Wert von module.exports Wert der Exporte. Wenn der Exportwert abgerufen werden kann, setzen Sie den Status auf „Ausgeführt“.

Eines ist zu beachten: Wenn Sie ein Objekt exportieren möchten, indem Sie den Exporten einen Wert zuweisen, ist

define(function(require,exports,module){
 exports ={
  add: function(a,b){
    return a+b;
  }
 }
})

nicht erfolgreich. Wir beurteilen den Wert der endgültig exportierten Exporte, indem wir die oben genannten Schritte ausführen Erstens hat die Funktion keinen Rückgabewert. Zweitens ist mod.exports undefiniert und die endgültigen Exporte sind undefiniert. Warum passiert das? Es wird durch die Referenzzuweisung in js verursacht. Die Zuweisungsstrategie von js lautet „Pass by Sharing“. Obwohl exports === module.exports anfänglich, wenn ein Objekt exportiert wird, zeigt exports auf das Objekt, aber module.exports wurde noch nicht initialisiert und ist daher undefiniert Etwas wird schief gehen. Die korrekte Schreibweise

ist

define(function(require,exports,module){
 module.exports ={
  add: function(a,b){
    return a+b;
  }
 }
})

Zusammenfassung

Man kann sagen, dass die Implementierung des Kernmoduls von Seajs erklärt wurde und ich eine gesehen habe viele Programmierkenntnisse und den Rückrufmodus kennengelernt. Einfallsreichtum und Berücksichtigung von Details. Jeder Teil des Codes berücksichtigt die Gefahren von Speicherlecks und diesem Zeigerreferenzversatz und trifft aktive Vorsichtsmaßnahmen. Dieser Geist ist es wert, gelernt zu werden.

Weitere Artikel zum Laden von Abhängigkeiten zwischen SeaJS-Modulen und zur Ausführung von Modulen finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn