ホームページ php教程 PHP开发 seajs モジュール間の依存関係の読み込みとモジュールの実行

seajs モジュール間の依存関係の読み込みとモジュールの実行

Dec 09, 2016 pm 02:21 PM

この記事では、seajs モジュール間の依存関係の読み込みとモジュールの実行について説明します。以下では詳しく説明しません。

エントリーメソッド

どのプログラムにも c の main 関数と同様のエントリーメソッドがあり、seajs も例外ではありません。シリーズ 1 のデモでは、ホームページのエントリー方法である seajs.use() を使用しています。エントリ メソッドは 2 つのパラメータを受け入れることができます。最初のパラメータはモジュール名、2 番目のパラメータはコールバック関数です。エントリ メソッドは新しいモジュールを定義します。この新しく定義されたモジュールは、入力パラメータによって提供されるモジュールに依存します。次に、ロードされた状態の後に新しいモジュールのコールバック関数が呼び出されるように設定します。このコールバック関数は主にすべての依存モジュールのファクトリ関数を実行し、最後にエントリ メソッドによって提供されるコールバックを実行します。

// 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 は、seajs が提供するプラグインをプリロードするために使用されます。これはメイン関数ではないため、無視できます。 Module.use はコア メソッドです。前述したように、このメソッドは新しいモジュールを作成し、コールバック関数を設定し、最後に新しいモジュールのすべての依存モジュールをロードします。

依存関係を読み込むloadメソッド

loadメソッドはseajsの本質とも言えます。このメソッドは主に依存モジュールをロードし、依存モジュールのコールバック関数を順番に実行します。最後のコールバック関数は、seajs.use("./name") によって作成された新しいモジュールのコールバック (mod.callback) です。

load メソッドは、依存モジュールを再帰的にロードします。依存モジュールが他のモジュールにも依存している場合は、このモジュールをロードします。これは、Module クラスの _waitings と _remain によって実現されます。

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
}
ログイン後にコピー

まず、モジュールの _waitings 属性と _remain 属性を初期化します。_remain が 0 の場合は、依存関係がないか、依存関係がロードされていることを意味します。0 でない場合は、onload 関数を実行できます。アンロードされたモジュール。ここには、すべての依存関係を同時にロードするためのちょっとした実装のコツがあります: requestCache オブジェクトは、ロード関数を保存します: (fetch 関数で定義)

if (!emitData.requested) {
 requestCache ?
  requestCache[emitData.requestUri] = sendRequest :
  sendRequest()
 }
ログイン後にコピー

その中で、sendRequest 関数は次のように定義されています。 :

function sendRequest() {
 seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)
 }
ログイン後にコピー

すべての依存関係を並列ロードします。依存関係がロードされると、onRequest コールバックが実行され、依存モジュールがなくなるまで依存関係をロードします。

最上位の依存関係がモジュールに依存しなくなったら、onload 関数を実行し、関数本体でステータスをロード済みに設定し、mod.callback を実行して、モジュールの _waitings 属性を確認して設定し、下位レベルの依存関係がモジュールに依存しているかどうかを判断します。モジュールにまだ依存関係がある場合、下位モジュールの mod.callback が実行され、最終的には seajs.use を通じて作成された匿名モジュールの mod.callback が実行されます。

簡単な例を使用して、上記のプロセスを示します:

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));
})
ログイン後にコピー

デバッグ ツールを通じて、onload が実行される順序を確認できます:

最後に、匿名モジュールのステータスコードは 4 、つまりモジュールは実行されていません。実際、匿名モジュールにはファクトリ関数が定義されていないため、モジュール実行の

Exec が呼び出されます。 seajs.use で定義された mod.callback 内で順番に呼び出され、依存するすべての exec メソッドがプログラム ロジックを実行します。 exec メソッドには、require、exports などの commonJS の重要なキーワードまたは関数がいくつかあります。見てみましょう:

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 関数はモジュールを取得し、モジュールのファクトリ関数を実行して、戻り値。 require 関数のsolve メソッドは、対応するモジュール名の絶対 URL を取得し、require 関数の async メソッドは依存関係を非同期に読み込み、コールバックを実行します。ファクトリ メソッドの戻り値の場合、ファクトリ メソッドがオブジェクトの場合は、exports の値になります。ファクトリ メソッドに戻り値がある場合は、exports の値または module.exports の値になります。輸出額。エクスポート値が取得できたら、ステータスを実行済みに設定します。

注意すべき点: オブジェクトに値を代入してエクスポートする場合

define(function(require,exports,module){
 exports ={
  add: function(a,b){
    return a+b;
  }
 }
})
ログイン後にコピー

が失敗する場合 まず、上記のメソッドを実行して、最終的にエクスポートされたエクスポートの値を判断します。関数は値を返しません。第二に、mod.exports は未定義であり、最終的にエクスポートされる ,exports は未定義です。なぜこのようなことが起こるのでしょうか? jsでの参照代入が原因です。 jsの代入方針は「共有による受け渡し」です。最初はexports === module.exportsですが、オブジェクトがexportsに代入されると、exportsはオブジェクトを指しますが、module.exportsはまだ初期化されておらず、未定義であるため、何かがうまくいかないでしょう。

正しい書き方は

define(function(require,exports,module){
 module.exports ={
  add: function(a,b){
    return a+b;
  }
 }
})
ログイン後にコピー

です。

概要

seajsのコアモジュールの実装について多くのコーディングスキルを見て、その創意工夫を評価したと言えます。コールバック モードと微妙な点の考慮。コードのすべての部分でメモリ リークとこのポインタ参照オフセットの危険性が考慮されており、この精神は学ぶ価値があります。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)