Seseorang bertanya kepada saya hari ini bagaimana menerapkan bilah kemajuan pemuatan Javascript seperti kotak surat 163.
Saya tidak tahu, tetapi tidak sulit untuk mengimplementasikannya, karena <script /> memiliki onload dan onreadystatechange. Juga, kami memiliki Atlas.
Ada kelas di Atlas: Sys.ScriptLoader, fungsinya untuk memuat beberapa file Script dalam satu halaman secara berurutan. Sebelum mengimplementasikannya, mari kita analisa kode kelas ini.
1Sys.ScriptLoader = fungsi() {
2
3 //Array objek referensi untuk semua Skrip.
4 var _referensi;
5 //Fungsi panggilan balik dijalankan setelah semua Skrip dimuat.
6 var _completionCallback;
7 // Konteks (parameter) yang diberikan saat menjalankan fungsi panggilan balik.
8 var _callbackContext;
9
10 // Elemen HTTP (<script />) dari Script yang sedang dimuat.
11 var _currentLoadingReference;
12 // Fungsi panggilan balik dipanggil setelah Script saat ini dimuat.
13 var _currentOnScriptLoad;
14
15 // Satu-satunya metode ScriptLoader adalah meneruskan tiga parameter. Arti dari parameter tersebut tidak akan terulang.
16 this.load = function(referensi, penyelesaianCallback, callbackContext) {
17 _references = referensi;
18 _completionCallback = penyelesaianCallback;
19 _callbackContext = panggilan balikContext;
20
21 memuatReferensi();
dua puluh dua }
dua puluh tiga
24 // Mulai memuat referensi.
25 fungsi loadReferences() {
26 // Jika Script sedang dimuat.
27 // Artinya metode ini tidak dipanggil pertama kali, tetapi dimuat dalam Script
28 // Dipanggil setelah selesai untuk memuat Script berikutnya.
29 jika (_currentLoadingReference) {
30 // Periksa readyState elemen Script saat ini, yang selesai di IE.
31 // Browser lain seperti FF dimuat (FF sebenarnya tidak memiliki atribut ini.
32 // Namun kode di bawah ini akan mengaturnya agar dimuat).
33 // Jika pemuatan gagal, keluar.
34 if ((_currentLoadingReference.readyState != 'dimuat') &&
35 (_currentLoadingReference.readyState != 'selesai')) {
36 kembali;
37 }
38 lainnya {
39 // Memasuki cabang ini menunjukkan pemuatan berhasil.
40
41 // Jika Script saat ini mendefinisikan fungsi onLoad.
42 jika (_currentOnScriptLoad) {
43 // Dipanggil melalui eval (inilah masalahnya).
44 eval(_currentOnScriptLoad);
45 //Setel ke null untuk melepaskan sumber daya.
46 _currentOnScriptLoad = nol;
47 }
48
49 // Tetapkan kejadian terkait ke null untuk memastikan sumber daya dilepaskan.
50 jika (Sys.Runtime.get_hostType() != Sys.HostType.InternetExplorer) {
51 // Jika browser saat ini bukan IE, lihat kode di bawah
52 // Anda akan menemukan bahwa event onload didefinisikan untuk <script />.
53 _currentLoadingReference.onload = null;
54 }
55 lainnya {
56 // Jika itu IE, lihat kode di bawah dan Anda akan menemukannya
57 // <script /> mendefinisikan event onreadystatechange.
58 _currentLoadingReference.onreadystatechange = null;
59 }
60
61 //Akhirnya lepaskan referensi <script /> saat ini.
62 _currentLoadingReference = nol;
63}
64}
65
66 // Jika masih ada Script yang dibongkar.
67 if (_references.length) {
68 // Dequeue.
69 referensi var = _references.dequeue();
70 // Membuat <skrip />
71 var scriptElement = document.createElement('script');
72 //Atur <script /> saat ini dan fungsi panggilan balik saat ini agar pemuatan berhasil.
73 _currentLoadingReference = scriptElement;
74 _currentOnScriptLoad = referensi.onscriptload;
75
76 if (Sys.Runtime.get_hostType() != Sys.HostType.InternetExplorer) {
77 // Jika bukan IE, setel atribut readyState untuk <script />.
78 // Dan gunakan event onload.
79 scriptElement.readyState = 'dimuat';
80 scriptElement.onload = loadReferences;
81 }
82 lainnya {
83 // Jika IE, gunakan event onreadystatechange.
84 scriptElement.onreadystatechange = loadReferences;
85}
86 scriptElement.type = 'teks/javascript';
87 scriptElement.src = referensi.url;
88
89 // Tambahkan <skrip /> ke DOM
90 var headElement = document.getElementsByTagName('head')[0];
91 headElement.appendChild(scriptElement);
92
93 kembali;
94}
95
96 // Jika eksekusi mencapai titik ini, berarti semua skrip telah dimuat.
97 // Jika fungsi panggilan balik yang dijalankan setelah semua Skrip dimuat telah ditentukan,
98 // Lalu jalankan dan lepaskan sumber daya.
99 jika (_completionCallback) {
100 var penyelesaianCallback = _completionCallback;
101 var callbackContext = _callbackContext;
102
103 _completionCallback = nol;
104 _callbackContext = nol;
105
106 penyelesaianCallback(callbackContext);
107 }
108
109 _referensi = nol;
110 }
111}
112Sys.ScriptLoader.registerClass('Sys.ScriptLoader');
Terlihat bahwa cara Sys.ScriptLoader memuat skrip adalah dengan menambahkan elemen <script /> ke <header /> secara berurutan melalui kode. Faktanya, ini sangat jarang digunakan di Atlas.
Faktanya, kode Sys.ScriptLoader sangat sederhana, dan komentar yang saya tambahkan sepertinya tidak berguna. Perlu dicatat bahwa semua sumber daya dilepaskan semaksimal mungkin. Berikan perhatian khusus pada kode yang dimulai dari baris 99. Badan if pertama-tama menggunakan variabel sementara untuk mempertahankan dua variabel global, dan kemudian melepaskan variabel global. Tujuannya adalah untuk menghindari kebocoran memori yang disebabkan oleh pengecualian yang dilemparkan ketika penyelesaianCallback dijalankan, meskipun kemungkinannya hanya satu dari sepuluh ribu. Semakin banyak Javascript, semakin mudah menyebabkan kebocoran memori. Sebaiknya perhatikan masalah ini saat menulis kode JS.
Selanjutnya, jelaskan parameter pertama dari metode load, referensi. Awalnya saya mengira ini adalah array kelas Sys.Reference, tetapi ternyata ternyata sangat berbeda. Bagaimanapun, lihatlah kode kelas ini.
1Sys.Referensi = fungsi() {
2
3 var _komponen;
4 var _onload;
5
6 ini.get_component = fungsi() {
7 kembalikan _komponen;
8}
9 this.set_component = fungsi(nilai) {
10 _komponen = nilai;
11 }
12
13 ini.get_onscriptload = fungsi() {
14 kembalikan _onload;
15}
16 this.set_onscriptload = fungsi(nilai) {
17 _onload = nilai;
18}
19
20 ini.buang = fungsi() {
21 _komponen = nol;
dua puluh dua }
dua puluh tiga
24 ini.getDescriptor = fungsi() {
25 var td = Sys.TypeDescriptor();
26
27 td.addProperty('komponen', Objek);
28 td.addProperty('onscriptload', String);
29 kembali td;
30}
31}
32Sys.Reference.registerSealedClass('Sys.Reference', null, Sys.ITypeDescriptorProvider, Sys.IDisposable);
33Sys.TypeDescriptor.addType('skrip', 'referensi', Sys.Referensi);
Memperhatikan kode kelas Sys.ScriptLoader, kita dapat melihat bahwa setiap elemen array referensi sebenarnya hanyalah "{ url : " http://www.sample.com/sample.js ", onscriptload : " peringatan(1)"}" objek formulir. Tapi ini tidak masalah, Anda dapat dengan mudah menggunakan JSON untuk membuat array seperti itu.
Pada titik ini, saya rasa semua orang seharusnya sudah memikirkan cara menggunakan Sys.ScriptLoader untuk membuat bilah kemajuan pemuatan JS dengan mudah. Namun sekarang setelah saya tulis di sini, saya akan terus menerapkannya dengan cara yang sederhana.
Yang pertama adalah file aspx.
1<%@ Halaman Bahasa="C#" %>
2
3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
4
5<skrip runat="server">
6
7</skrip>
8
9<html xmlns=" http://www.w3.org/1999/xhtml " >
10<kepala runat="server">
11 <title>Muat Skrip</title>
12 <bahasa skrip="javascript">
13 fungsi Memuat()
14 {
15 dokumen.getElementById("bar").style.width = "0px";
16 skrip var = Array baru();
17 untuk (var i = 0; i < 8; i++)
18 {
19 var s = Objek baru();
20 var tidur = Math.round((Math.random() * 400)) + 100;
21 s.url = "Script.ashx?sleep=" + tidur + "&t=" + Math.random();
22 detik biaya = tidur;
23 skrip.push;
dua puluh empat }
25
26 Jeffz.Sample.LoadScripts.load(skrip);
27}
28 </skrip>
29</kepala>
30<body style="font-family: Arial;">
31 <form id="form1" runat="server">
32 <div>
33 <atlas:ScriptManager ID="ScriptManager1" runat="server">
34 <Skrip>
35 <atlas:Jalur ReferensiScript="js/LoadScripts.js" />
36 </Skrip>
37 </atlas:Manajer Skrip>
38
39 Bilah Kemajuan:
40 <div style="perbatasan: solid 1px hitam;">
41 <div id="bar" style="tinggi: 20 piksel; lebar:0%; warna latar:Merah;"></div>
42 </div>
43 <input type="button" onclick="Muat()" value="Muat" />
44 <div id="pesan"></div>
45 </div>
46 </bentuk>
47</tubuh>
48</html>
Sangat sederhana. Bilah kemajuan paling sederhana dibuat menggunakan dua DIV. Fungsi Load() dipanggil ketika tombol diklik. Fungsi ini secara acak menghasilkan tautan skrip dan menghasilkan larik skrip 8 elemen. Format array scripts adalah sebagai berikut:
1var scripts =
2[
3 { url : " http://www.sample.com/sample1.js ", biaya : costOfLoading1 },
4 { url : " http://www.sample.com/sample2.js ", biaya : costOfLoading2 },
5 { url : " http://www.sample.com/sample3.js ", biaya : costOfLoading3 }
6];
Tak perlu dikatakan lagi, atribut url setiap elemen, dan fungsi biaya adalah untuk mewakili nilai waktu yang dihabiskan untuk memuat file. Nilai ini tidak mempunyai satuan, yang digunakan hanya proporsi nilai tersebut terhadap total konsumsi. Selain itu, Anda dapat melihat bahwa ada Script.ashx, yang digunakan untuk mensimulasikan pemuatan skrip yang lama. Ini akan menidurkan thread untuk jangka waktu tertentu berdasarkan nilai sleep di string kueri (seperti untuk t berikut, tujuannya hanya untuk menghindari klik tombol dengan mengubah cache browser querystring), file ini hampir tidak memiliki kode dan implementasinya dapat dilihat pada contoh download. Terakhir, dimuat dengan memanggil metode Jeffz.Sample.LoadScripts.load, yang melibatkan kode berikut, LoadScripts.js:
1Type.registerNamespace('Jeffz.Sample');
2
3Jeffz.Sample.LoadScripts = fungsi baru()
4{
5 var totalBiaya = 0;
6 var scriptLoader = Sys.ScriptLoader() baru;
7
8 this.load = fungsi(skrip)
9 {
10 jika (Jeffz.Sample.__onScriptLoad != null)
11 {
12 lempar Kesalahan baru("Sedang berlangsung");
13}
14
15 totalBiaya = 0;
16 Jeffz.Sample.__onScriptLoad = onScriptLoad;
17 referensi var = Array baru();
18
19 var LoadCost = 0;
20 untuk (var i = 0; i < panjang skrip; i++)
dua puluh satu {
22 totalBiaya += skrip[i].biaya;
23 LoadCost += skrip[i].biaya;
dua puluh empat
25 var ref = createReference(skrip[i].url, LoadedCost);
26
27 referensi.push(ref);
28 }
29
30 scriptLoader.load(referensi, onComplete);
31}
32
33 fungsi createReference(url, LoadedCost)
34 {
35 var ref = Objek baru();
36 ref.url = url;
37 ref.onscriptload = "Jeffz.Sample.__onScriptLoad('" + url + "', " + LoadedCost + ")";
38 wasit kembali;
39 }
40
41 fungsi padaLengkap()
42 {
43 Jeffz.Sample.__onScriptLoad = null;
44}
45
46 fungsi onScriptLoad(url, LoadCost)
47 {
48 var kemajuan = 100,0 * LoadCost / totalCost;
49 document.getElementById("bar").style.width = kemajuan + "%";
50 document.getElementById("message").innerHTML += ("<strong>" + url + "</strong>" + " dimuat.<br />");
51 }
52}
Sayangnya, sepertinya kode tersebut tidak perlu dijelaskan sama sekali. Sejauh ini, bilah kemajuan pemuatan skrip sederhana telah selesai, yang cukup sederhana. Kode dapat diunduh dengan mengklik di sini, atau melihat efeknya dengan mengklik di sini.
Namun apakah itu akhir dari permasalahannya? Faktanya, saya tidak terlalu puas dengan solusi ini, meskipun solusi ini seharusnya cukup untuk sebagian besar situasi. Anda dapat melihat bahwa saya mengimplementasikan Jeffz.Sample.LoadScripts sebagai Singleton, artinya tidak ada contoh lain yang seperti itu. Dan di awal metode memuat, dinilai apakah sedang memuat. Jika demikian, pengecualian akan dilempar. Alasan langsung untuk mencapai pemuatan "utas tunggal" adalah karena hal ini dibatasi oleh penerapan Sys.ScriptLoader.
Silakan lihat baris 44 dari kode Sys.ScriptLoader. Ini menggunakan eval untuk panggilan balik "jahat" ketika skrip dimuat. Ini sebenarnya adalah implementasi yang sangat tidak nyaman bagi pengembang, karena eval tidak mungkin meneruskan referensi ke suatu fungsi sebagai fungsi panggilan balik. Satu-satunya hal yang dapat dilakukan adalah meneruskan "kode root" ke Sys.ScriptLoader sebagai string. Meskipun masih mungkin untuk mencapai pemuatan Skrip "bersamaan" melalui Sys.ScriptLoader (terus terang, paling banyak Anda dapat membuat antrian seperti Sys.ScriptLoader), jumlah kode secara alami akan meningkat, dan kompleksitas pengembangan juga akan meningkat. meningkatkan.
Namun, menurut saya pemuatan skrip "utas tunggal" ini cukup untuk sebagian besar situasi. Dan jika memang ada persyaratan "khusus", bukankah mudah bagi sebagian besar pengembang untuk menulis ulang persyaratan tersebut dengan mengacu pada contoh jelas Sys.ScriptLoader?
http://www.cnblogs.com/JeffreyZhao/archive/2006/09/13/502357.html