Pemuatan modul sebenarnya membagi JS menjadi banyak modul untuk pengembangan dan pemeliharaan yang mudah. Oleh karena itu, saat memuat banyak modul JS, perlu memuat secara dinamis untuk meningkatkan pengalaman pengguna.
Sebelum memperkenalkan pustaka pemuatan modul, kami akan memperkenalkan metode.
Pemuatan Dinamis Metode JS:
Salinan kode adalah sebagai berikut:
fungsi loadjs (url, callback) {
var node = document.createelement ("script");
node [window.addeventlistener? "onload": "onreadystatechange"] = function () {
if (window.addeventListener || /Loaded|compete/i.test(node.readyState)) {
callback ();
node.onreadystatechange = null;
}
}
node.onError = function () {};
node.src = url;
var head = document.geteLementsbyTagname ("head") [0];
head.insertbefore (node, head.firstchild); // Sebelum memasukkannya ke dalam simpul pertama kepala, mencegah tag kepala di bawah IE6 ditutup, dan gunakan AppendChild untuk melaporkan kesalahan.
}
Karena Situ Zhengmei menggunakan kerangka kerja massa yang ditulisnya untuk memperkenalkan pemuatan modul, yang paling banyak digunakan dalam industri adalah membutuhkan.js dan Sea.js. Karena itu, saya pikir dia memiliki kepribadian yang kuat.
Izinkan saya berbicara tentang proses pemuatan Sea.js:
Halaman Chaosan.js diperkenalkan di tag kepala, dan objek Seajs akan diperoleh.
Juga perkenalkan index.js.
Kode index.js adalah sebagai berikut:
Salinan kode adalah sebagai berikut:
seajs.use (['./ a', 'jQuery'], function (a, $) {
var num = aa;
$ ('#J_a'). Teks (num);
})
A.JS:
Salinan kode adalah sebagai berikut:
Tentukan (fungsi (membutuhkan, ekspor, modul) {
var b = membutuhkan ('./ B');
var a = function () {
return 1 + parseInt (bb ());
}
ekspor.a = a;
})
B.JS:
Salinan kode adalah sebagai berikut:
Tentukan (fungsi (membutuhkan, ekspor, modul) {
var c = membutuhkan ('./ C');
var b = function () {
return 2 + parseInt (cc ());
}
ekspor.b = b;
})
C.JS:
Salinan kode adalah sebagai berikut:
Tentukan (fungsi (membutuhkan, ekspor, modul) {
var c = function () {
kembali 3;
}
ekspors.c = c;
})
Dari yang di atas, kita dapat melihat modul itu tergantung pada B, dan B tergantung pada c.
Ketika program memasuki index.js, Seajs akan memanggil metode penggunaan.
Salinan kode adalah sebagai berikut:
seajs.use = function (ids, callback) {
GlobalModule._use (IDS, Callback)
}
Deskripsi: Ketika GlobalModule diinisialisasi dalam Seajs (ketika Sea.js diperkenalkan), contoh modul var globalmodule = modul baru (util.pageuri, status.compiled)
Pada saat ini ids -> ['./a' ,'jQuery'], callback -> function (a, $) {var num = aa; $ ('#j_a'). Teks (num);}
Selanjutnya, GlobalModule._use (IDS, Callback) akan dipanggil
Salinan kode adalah sebagai berikut:
Module.prototype._use = function (ids, callback) {
var uris = resolve (ids, this.uri); // Resolusi ['./a' ,'Jquery']
this._load (uris, function () {// Panggil alamat modul A dan jQuery yang diurai [url1, url2] dan hubungi metode _Load.
//util.map: Biarkan semua anggota data menjalankan fungsi yang ditentukan pada suatu waktu dan mengembalikan array baru, yang merupakan hasil dari eksekusi panggilan balik anggota array asli
var args = util.map (uris, function (uri) {
Kembalikan URI? CachedModules [uri] ._ compile (): null; // Jika url ada, hubungi metode _compile.
})
if (callback) {callback.apply (null, args)}
})
}
Karena setelah memanggil metode _Load, dua fungsi callback akan muncul, jadi kami menandai fungsi (a, $) {var num = aa; $ ('#j_a'). Teks (num);} ke callback1,
Atur this._load (URIS, function () {}) Bendera metode panggilan balik ke callback2.
Metode Resolve adalah untuk menyelesaikan alamat modul, jadi saya tidak akan membahas detail di sini.
Akhirnya, URI di var uris = resolve (ids, this.uri) diuraikan ke ['http: //localhost/test/seajs/a.js' ,'http: //localhost/test/seajs/lib/juqery/1.7.2/ruqery.
Dan selanjutnya ini._load akan dieksekusi
Salinan kode adalah sebagai berikut:
// Metode _Load () terlebih dahulu akan menentukan file sumber daya mana yang belum siap. Jika semua file sumber daya dalam keadaan siap, Callback2 akan dieksekusi.
// Dalam hal ini, kami juga akan membuat ketergantungan melingkar dan melakukan pemuatan pada JS yang tidak diturunkan
Module.prototype._load = function (URIS, callback2) {
//util.filter: Biarkan semua anggota data menjalankan fungsi yang ditentukan pada satu waktu dan mengembalikan array baru. Array adalah anggota yang mengembalikan true setelah melakukan panggilan balik dari anggota array asli.
// bongkar muat adalah berbagai modul yang tidak dikompilasi
var ucloadeduris = util.filter (URIS, function (uri) {
// Mengembalikan anggota yang fungsi eksekusi nilai boolean benar, mengembalikan benar ketika URI ada dan tidak ada dalam cachemodule variabel internal atau menyimpan nilai status kurang dari status. Tetap dalam informasi penyimpanan
// Jika status. Nilai siap 4, jika kurang dari empat, ada kemungkinan bahwa itu sedang diambil dan diunduh.
kembalikan uri && (! CachedModules [uri] ||
CachedModules [URI] .Status <status.ready)
});
// Jika semua modul dalam URI siap, jalankan panggilan balik dan keluar dari badan fungsi (kali ini metode _compile modul akan dipanggil).
var length = Uploadeduris.length
if (length === 0) {callback2 () return}
// Jumlah modul yang tidak dimuat
var tetap = panjang
// Buat penutupan dan cobalah memuat modul yang tidak dimuat
untuk (var i = 0; i <panjang; i ++) {
(function (uri) {
// menilai jika informasi penyimpanan URI tidak ada di variabel internal cacheedmodules, instantiate objek modul
VAR MODULE = CACHEDMODUS [URI] ||
(CachedModules [URI] = Modul baru (URI, Status.Fetching))
// Jika nilai status modul lebih besar dari atau sama dengan 2, itu berarti bahwa modul telah diunduh dan sudah ada secara lokal. Pada saat ini, OnFetched () dieksekusi
// Kalau tidak, ambil (uri, onfetched) dipanggil untuk mencoba mengunduh file sumber daya. Onload akan dipicu setelah file sumber daya diunduh, dan metode OnFetched akan dieksekusi di Onload.
module.status> = status.fetched? onfetched (): fetch (uri, onfetched)
fungsi onfetched () {
Modul = CachedModules [URI]
// Ketika nilai status modul lebih besar dari atau sama dengan status.
if (module.status> = status.saved) {
// GetPurePendencies: Dapatkan array ketergantungan tanpa ketergantungan melingkar
var deps = getPurePendencies (modul)
// Jika array ketergantungan tidak kosong
if (deps.length) {
// Jalankan metode _load () lagi sampai semua dependensi dimuat dan panggilan balik dieksekusi setelah pemuatan semua dependensi selesai
Module.prototype._load (deps, function () {
CB (modul)
})
}
// Jika array dependensi kosong, jalankan CB (modul) secara langsung
kalau tidak {
CB (modul)
}
}
// Jika akuisisi gagal, seperti 404 atau tidak mematuhi spesifikasi modular
// Dalam hal ini, module.status akan dipertahankan saat pengambilan atau diambil
kalau tidak {
CB ()
}
}
}) (Usloadeduris [i])
}
// Metode CB - Jalankan panggilan balik setelah memuat semua modul
fungsi cb (modul) {
// Jika informasi penyimpanan modul ada, maka modifikasi nilai status dalam informasi penyimpanan modul dan ubah menjadi status.
modul && (module.status = status.ready)
// Callback dieksekusi hanya ketika semua modul dimuat.
---bemain === 0 && callback2 ()
}
}
}
Here, the array length of unLoadedUris is 2, ['http://localhost/test/SEAJS/a.js','http://localhost/test/SEAJS/lib/juqery/1.7.2/juqery-debug.js'], so two closures with the name of the js path will be generated next.
Ambil http: //localhost/test/seajs/a.js sebagai contoh
Berikutnya: Pertama, modul akan dibuat:
Salinan kode adalah sebagai berikut:
CachedModules ('http: //localhost/test/seajs/a.js') = modul baru ('http: //localhost/test/seajs/a.js',1)
module.status> = status.fetched? onfetched (): fetch (uri, onfetched)
Karena modul A tidak dimuat pada saat ini, ambil (uri, onfetched) akan dieksekusi selanjutnya, yaitu, fetch ('http: //localhost/test/seajs/a.js', tidak dipahami).
Salinan kode adalah sebagai berikut:
fungsi fetch (uri, onfetched) {
// Ganti URI dengan alamat permintaan baru sesuai dengan aturan di peta
var requesturi = util.parsemap (URI)
// Pertama, cari tahu apakah catatan permintaan terkandung dalam daftar yang diperoleh
if (fetchedlist [requesturi]) {
// Saat ini, refresh informasi penyimpanan modul dari URI asli ke permintaan yang didefinisikan ulang oleh peta
CachedModules [URI] = CachedModules [Requesturi]
// Jalankan Onfetched and Return, yang berarti bahwa modul telah berhasil diperoleh
onfetched ()
Kembali
}
// Informasi penyimpanan permintaan permintaan di daftar peroleh
if (fetchinglist [requesturi]) {
// Tambahkan panggilan balik yang sesuai dengan URI di CallbackList dan kembali
CallbackList [Requesturi] .Push (onfetched) // Jika sedang diambil, dorong metode panggilan balik yang dipenuhi dari modul ini ke dalam array dan kembalikan.
Kembali
}
// Jika modul yang Anda coba peroleh tidak muncul di fetchedlist dan fetchinglist, tambahkan informasi mereka di daftar permintaan dan daftar panggilan balik masing -masing
fetchinglist [requesturi] = true
CallbackList [requesturi] = [OnFetched]
// Ambillah
Module._fetch (
requesturi,
fungsi() {
fetchedlist [requesturi] = true
// Pembaruan Status Modul
// Jika module.status sama dengan status.fectching, ubah status modul untuk diambil
Modul var = CachedModules [URI]
if (module.status === status.fetching) {
module.status = status.fetched
}
if (fetchinglist [requesturi]) {
Hapus FetchingList [Requesturi]
}
// Panggilan CallbackList Unified Eksekusi Callbacks
if (callbackList [requesturi]) {
util.foreach (callbacklist [requesturi], function (fn) {
fn () // fn adalah metode onFeched yang sesuai dengan modul a.
})
Hapus CallbackList [Requesturi]
}
},
config.charset
)
}
Selanjutnya, module._fetch () akan dieksekusi, dan kami memanggil fungsi callback di sini sebagai callback3.
Metode ini adalah memanggil metode LoadJS untuk mengunduh file A.JS secara dinamis. (Karena ada dan jQuery, dua skrip baru akan dibuat). Ada pertanyaan di sini. Jika Anda membuat skrip untuk A dan menambahkannya ke kepala, Anda akan mengunduh file JS. Namun, di Seajs, itu tidak diunduh. Sebaliknya, Anda akan menunggu sampai skrip untuk jQuery dibuat dan ditambahkan ke kepala sebelum Anda mengunduhnya (Google Debugger menetapkan breakpoint, dan itu terus menunjukkan menunggu menunggu). Apakah ini untuk mao?
(Direkomendasikan di sini: http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff. Saya akan berbicara tentang pertanyaan tambahan di sini. Anda mungkin tahu mengapa kita perlu menggunakan tabel untuk lebih sedikit tata letaknya, karena wawancara yang sama, pada waktu yang sama, pada saat itu, wawancara itu perlu divise, sementara wawancara yang sama, pada waktu yang sama, pada saat itu, wawancara itu perlu divise. Sebelum itu akan ditampilkan, dan div akan ditampilkan sebanyak yang diuraikan.
Setelah unduhan berhasil, itu akan diuraikan dan dieksekusi, dan metode define dieksekusi. Di sini kita pertama -tama akan menjalankan kode modul a.
Define (id, deps, function () {}) analisis metode
Salinan kode adalah sebagai berikut:
// Tentukan Definisi, ID: ID Modul, DEPS: Ketergantungan Modul, Pabrik
Module._define = function (id, deps, factory) {
// Selesaikan dependensi // jika deps bukan tipe array, pabrik adalah fungsi
if (! util.isArray (deps) && util.isfunction (factory)) {// Badan fungsi secara teratur cocok dengan string membutuhkan dan membentuk array untuk mengembalikan tugas ke DEPS
deps = util.parsedependencies (factory.tostring ())
}
// Tetapkan informasi meta
var meta = {id: id, dependensi: deps, pabrik: pabrik}
if (document.attachevent) {
// Dapatkan simpul skrip saat ini
var skrip = util.getCurrentScript ()
// jika ada node skrip
if (skrip) {
// Dapatkan alamat URI asli
Deriveduri = util.unparsemap (util.getscriptabsolutesrc (skrip))}
if (! DueDuri) {
util.log ('gagal mendapatkan uri dari skrip interaktif untuk:', factory.tostring (), 'warn')
}
}
.........
}
Tentukan pertama -tama akan melakukan penilaian pada pabrik untuk menentukan apakah itu fungsi (alasannya adalah bahwa definisi tersebut juga dapat menyertakan file dan objek)
Jika itu adalah fungsi, maka fungsi akan diperoleh melalui pabrik.
Untuk A.JS, ketergantungannya adalah B.JS jadi deps adalah ['./b']
Dan simpan informasi a.js var meta = {id: id, dependensi: deps, pabrik: pabrik}
Untuk a.js meta = {id: undefined, dependencies: ['./b'], factory: function (xxx) {xxx}}
Di browser IE 6-9, Anda bisa mendapatkan jalan untuk menjalankan JS. Namun, di browser standar, ini tidak layak, sehingga Anda dapat menetapkan informasi meta ke anonymousModulemeta = meta.
Kemudian memicu Onload, dan Callback Metode Callback3 akan dipanggil. Metode panggilan balik ini akan memodifikasi nilai status modul callback saat ini (A.JS) dan mengaturnya ke module.status = status.fetched.
Selanjutnya, panggilan balik yang sesuai dengan A.JS dalam daftar panggilan balik panggilan balik akan dieksekusi secara seragam, yaitu, dipenuhi.
Metode OnFetched memeriksa apakah modul A memiliki modul dependen. Karena A tergantung pada B, jalankan _Load () pada b.js di mana modul A tergantung.
Modul B akan diunduh, dan metode definisi jQuery akan dieksekusi terlebih dahulu. Karena jQuery tidak bergantung pada modul, setelah panggilan balik onload. Onfetched Call Metode CB.
Ketika B diimplementasikan dalam proses yang sama dengan A, Modul C akan diunduh. Akhirnya, C, B, modul diunduh dan dieksekusi, dan setelah onload selesai, metode CB juga akan dipanggil (pertama C, lalu B, lalu C)
Setelah semua modul siap, metode callback2 akan dipanggil.
Akhirnya, panggilan balik disebut back2 dan metode _compile dari modul A dan jQuery dijalankan:
Pertama, kompilasi modul A.JS, dan jalankan fungsi modul a. Karena A telah membutuhkan (b.js) di dalamnya, ia akan menjalankan fungsi modul b.
Fungsi modul A memulai eksekusi
Fungsi modul B mulai mengeksekusi
Fungsi modul C memulai eksekusi
Eksekusi fungsi modul C telah selesai
Eksekusi fungsi modul B telah selesai
Eksekusi fungsi modul A telah selesai
Akhirnya, jalankan fungsi jQuery.
Setelah kompilasi, jalankan Callback1 dan Anda dapat menggunakan objek A dan JQuery.
PS: Versi Seajs telah diperbarui, dan tidak ada metode _Compile sekarang. (Semua orang pergi untuk melihatnya sendiri, saya ingin melihatnya juga)
Mari kita bicara tentang proses modul seajs compiled_compile.
Pertama, kompilasi A.JS
Salinan kode adalah sebagai berikut:
Module.prototype._compile = function () {
126 modul var = ini
127 // Jika modul telah dikompilasi, maka kembalikan modul. Exports secara langsung
128 if (module.status === status.compiled) {
129 Return Module.Exports
130}
133 // 1. File modul adalah 404.
134 // 2. File modul tidak ditulis dengan format modul yang valid.
135 // 3. Kasus kesalahan lainnya.
136 // Berikut adalah beberapa pengecualian untuk ditangani, dan kemudian kembali nol secara langsung
137 if (module.status <status.saved &&! Hasmodifiers (modul)) {
138 Return NULL
139}
140 // Ubah status modul untuk dikompilasi, yang berarti modul sedang dikompilasi
141 module.status = status.compiling
142
143 // Penggunaan internal modul adalah metode yang digunakan untuk mendapatkan antarmuka yang disediakan oleh modul lain (disebut submodul) dan beroperasi secara sinkron secara sinkron
144 fungsi membutuhkan (id) {
145 // jalur jalur modul sesuai dengan ID
146 Var URI = Resolve (id, Module.uri)
147 // Dapatkan modul dari cache modul (perhatikan bahwa dependensi submodule sebagai modul utama telah diunduh)
148 var anak = cacheedmodules [uri]
149
150 // Kembalikan NULL saat URI tidak valid.
151 // Jika anak kosong, itu hanya bisa berarti bahwa parameter diisi secara tidak benar, dan kemudian kembali nol secara langsung
152 if (! Child) {
153 kembali nol
154}
155
156 // Hindari panggilan melingkar.
157 // Jika status submodule adalah status.
158 if (child.status === status.compiling) {
159 Return Child. Exports
160}
161 // Arahkan ke modul yang memanggil modul saat ini selama inisialisasi. Berdasarkan properti ini, Anda bisa mendapatkan tumpukan panggilan saat modul diinisialisasi.
162 Child.parent = Modul
163 // kembalikan modul. Eksportasi anak yang disusun
164 Return Child._Compile ()
165}
166 // Digunakan secara internal untuk memuat modul secara asinkron dan menjalankan panggilan balik yang ditentukan setelah pemuatan selesai.
167 membutuhkan.async = fungsi (id, callback) {
168 MODULE._USE (IDS, Callback)
169}
170 // Gunakan mekanisme resolusi jalur di dalam sistem modul untuk menguraikan dan mengembalikan jalur modul. Fungsi ini tidak memuat modul, dan hanya mengembalikan jalur absolut yang diuraikan.
171 membutuhkan.resolve = function (id) {
172 Return Resolve (id, Module.uri)
173}
174 // Melalui properti ini, Anda dapat melihat semua modul yang dimuat oleh sistem modul.
175 // Dalam beberapa kasus, jika Anda perlu memuat ulang modul, Anda bisa mendapatkan URI dari modul, dan kemudian menghapus informasinya dengan menghapus kebutuhan.cache [URI]. Ini akan diperoleh ulang saat berikutnya Anda menggunakannya.
176 membutuhkan.cache = CachedModules
177
178 // MEMBUTUHKAN adalah metode untuk mendapatkan antarmuka yang disediakan oleh modul lain.
179 Module.equire = membutuhkan
180 // Ekspor adalah objek yang menyediakan antarmuka modul ke luar.
181 module.Exports = {}
182 Var Factory = Module.Factory
183
184 // Ketika pabrik adalah fungsi, itu mewakili konstruktor modul. Dengan menjalankan metode ini, Anda dapat memperoleh antarmuka yang disediakan oleh modul ke luar.
185 if (util.function (pabrik)) {
186 CompileStack.Push (Modul)
187 runinmoduleContext (pabrik, modul)
188 CompileStack.pop ()
189}
190 // Ketika pabrik adalah tipe non-fungsi seperti objek, string, dll., Antarmuka yang mewakili modul adalah objek, string, dan nilai lainnya.
191 // misalnya: define ({"foo": "bar"});
192 // misalnya: define ('I Am a Template. Nama saya {{name}}.');
193 lain jika (pabrik! == tidak ditentukan) {
194 Module.Exports = Pabrik
195}
196
197 // Ubah status modul yang dikompilasi, yang berarti modul telah dikompilasi
198 module.status = status.compiled
199 // Jalankan modifikasi antarmuka modul, melalui seajs.modify ()
200 execmodifiers (modul)
201 Return Module.Exports
202}
Salinan kode adalah sebagai berikut:
if (util.isfunction (factory)) {
186 CompileStack.Push (Modul)
187 runinmoduleContext (pabrik, modul)
188 CompileStack.pop ()
189}
Berikut adalah inisialisasi modul. Export. Metode RunInModuleContext:
Salinan kode adalah sebagai berikut:
// Jalankan kode modul sesuai dengan konteks modul
Fungsi 489 runinmoduleContext (fn, module) {
490 // Lulus dalam dua parameter yang terkait dengan modul dan modul itu sendiri
491 // Ekspor digunakan untuk mengekspos antarmuka
492 // Perlu digunakan untuk mendapatkan modul dependen (sinkron) (kompilasi)
493 var ret = fn (module.require, module.exports, module)
494 // Mendukung bentuk antarmuka paparan nilai pengembalian, seperti:
495 // return {
496 // fn1: xx
497 //, fn2: xx
498 // ...
499 //}
500 if (ret! == tidak terdefinisi) {
501 Module.Exports = ret
502}
503}
Jalankan metode fungsi dalam a.js, dan kemudian var b = membutuhkan ("b.js") akan dipanggil,
Metode yang membutuhkan akan mengembalikan nilai pengembalian metode kompilasi B, dan ada var c = membutuhkan ('c.js') dalam modul B.
Pada saat ini, metode kompilasi C akan dipanggil, dan kemudian fungsi C akan dipanggil. Dalam C, jika objek harus diekspos, atau objek pengembalian C dikembalikan, ekspor modul C akan ekspor = c. Atau langsung modul. Export = C; Singkatnya, modul C. Export = C akan dikembalikan pada akhirnya; jadi var c = module c. export = c. Dalam Modul B, Anda dapat menggunakan variabel C untuk memanggil metode dan sifat objek C dalam modul c.
Dengan analogi, modul A pada akhirnya dapat memanggil properti dan metode objek B dalam modul b.
Tidak peduli modul apa, selama Anda menggunakan modul.
Status modul akhir akan menjadi module.status = status. Compiled.
Salinan kode adalah sebagai berikut:
Module.prototype._use = function (ids, callback) {
var uris = resolve (ids, this.uri); // Resolusi ['./a' ,'Jquery']
this._load (uris, function () {// Panggil alamat modul A dan jQuery yang diurai [url1, url2] dan hubungi metode _Load.
//util.map: Biarkan semua anggota data menjalankan fungsi yang ditentukan pada suatu waktu dan mengembalikan array baru, yang merupakan hasil dari eksekusi panggilan balik anggota array asli
var args = util.map (uris, function (uri) {
Kembalikan URI? CachedModules [uri] ._ compile (): null; // Jika url ada, hubungi metode _compile.
})
if (callback) {callback.apply (null, args)}
})
}
Pada saat ini args = [Modul A.Export, modul jQuery.Export];
Salinan kode adalah sebagai berikut:
seajs.use (['./ a', 'jQuery'], function (a, $) {
var num = aa;
$ ('#J_a'). Teks (num);
})
Pada saat ini, A dan $ dalam fungsi adalah Modul A.Export dan Modul JQuery.Export.
Karena saya sekarang sedang mempelajari kode sumber jQuery dan desain kerangka kerja jQuery, saya berbagi beberapa pengalaman:
Kode sumber jQuery, saya telah membaca banyak analisis online, tetapi saya tidak bisa membacanya lagi saat saya melihatnya. Ini tidak terlalu berarti, jadi saya merekomendasikan analisis kode sumber jQuery Miaowei Classroom.
Desain kerangka kerja JavaScript Situ Zhengmei sulit, tetapi setelah membaca dengan cermat, Anda akan menjadi insinyur front-end senior.
Saya menyarankan belajar dan menggunakan Yu Bo's Sea.js, bagaimanapun, itu dibuat oleh orang Cina sendiri. Proyek atau rekonstruksi baru perusahaan kami akan dilakukan dengan menggunakan Seajs.
Berikutnya adalah pembacaan intensif kode sumber dari handbars modular dan tulang punggung MVC atau sudut MVVM. Di sini saya berharap seseorang akan memberi saya saran tentang buku, situs web, dan video apa yang harus dipelajari dengan cepat.