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-09 14:21:501135Durchsuche

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 wurde kann ausgeführt werden. Onload-Funktion; wenn nicht 0, entladene Module abrufen. Hier gibt es einen kleinen Implementierungstrick, der darin besteht, alle Abhängigkeiten gleichzeitig zu laden: Das requestCache-Objekt speichert die Ladefunktion: (in der Abruffunktion definiert)

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

wobei die sendRequest-Funktion wie folgt definiert ist:

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

lädt alle Abhängigkeiten parallel. Wenn die Abhängigkeiten geladen werden, erfolgt der onRequest-Rückruf wird ausgeführt, sprudelt nach oben 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));
})

Sie können es durch Debuggen sehen tools Zeigt die Ausführungsreihenfolge von onload an:

Schließlich ist ersichtlich, dass der Statuscode des anonymen Moduls 4 ist, was bedeutet, dass das Modul dort tatsächlich nicht ausgeführt wurde Für das anonyme Modul ist keine Factory-Funktion definiert. Die Ausführung ist nicht möglich.

Exec der Modulausführung

Die Modulausführung wird im in seajs.use definierten mod.callback und allen abhängigen exec-Methoden aufgerufen werden nacheinander aufgerufen, um die Programmlogik auszuführen. Es gibt einige wichtige Schlüsselwörter oder Funktionen von commonJS in der exec-Methode, wie zum Beispiel 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
}

require Funktionserfassungsmodul Und führen Sie die Factory-Funktion des Moduls aus, um den Rückgabewert zu 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 Exports einen Wert zuweisen, ist

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

erfolglos Der Wert der endgültig exportierten Exporte durch Ausführen der oben genannten Methode. Zweitens ist mod.exports undefiniert und die endgültig exportierten 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 ist, zeigt exports beim Zuweisen eines Objekts auf das Objekt, aber module.exports wurde noch nicht initialisiert und ist daher undefiniert Etwas wird schief gehen. Die richtige Schreibweise

ist

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

Zusammenfassung

Man kann sagen, dass die Implementierung des Kerns Modul von Seajs wurde erklärt, ich habe viele Programmierkenntnisse gesehen, den Einfallsreichtum des Rückrufmodus und die Berücksichtigung von Feinheiten geschätzt. 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.

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