سألني أحد الأشخاص اليوم عن كيفية تنفيذ شريط تقدم تحميل جافا سكريبت مثل صندوق البريد 163.
لا أعرف، ولكن ليس من الصعب تنفيذ ذلك، لأن <script /> يحتوي على onload وonreadystatechange. لدينا أيضا أطلس.
هناك فئة في Atlas: Sys.ScriptLoader، وظيفتها هي تحميل ملفات Script متعددة في الصفحة بالتسلسل. قبل تنفيذه، دعونا نحلل كود هذه الفئة.
1Sys.ScriptLoader = function() {
2
3 // مجموعة من الكائنات المرجعية لجميع البرامج النصية.
4 فار _references;
5 // يتم تنفيذ وظيفة رد الاتصال بعد تحميل جميع البرامج النصية.
6 فار _completionCallback;
7 // السياق (المعلمات) المقدم عند تنفيذ وظيفة رد الاتصال.
8 فار _callbackContext;
9
10 // عنصر HTTP (<script />) للبرنامج النصي الذي يتم تحميله حاليًا.
11 فار _currentLoadingReference;
12 // يتم استدعاء وظيفة رد الاتصال بعد تحميل البرنامج النصي الحالي.
13 فار _currentOnScriptLoad;
14
15 // الطريقة الوحيدة لـ ScriptLoader هي تمرير ثلاث معلمات لن يتكرر معنى المعلمات.
16 this.load = function(references,CompleteCallback,callbackContext) {
17 _references = مراجع;
18 _completionCallback =CompletionCallback;
19 _callbackContext = callbackContext;
20
21 LoadReferences();
إثنان وعشرون }
ثلاثة وعشرين
24 // ابدأ بتحميل المراجع.
25 دالة تحميل المراجع () {
26 // إذا كان البرنامج النصي قيد التحميل حاليًا.
27 // هذا يعني أن هذه الطريقة لا يتم استدعاؤها لأول مرة، ولكن يتم تحميلها في برنامج نصي
28 // يتم الاتصال به بعد الانتهاء لتحميل البرنامج النصي التالي.
29 إذا (_currentLoadingReference) {
30 // تحقق من حالة الاستعداد لعنصر البرنامج النصي الحالي المكتمل ضمن IE.
31 // يتم تحميل متصفحات أخرى مثل FF (ليس لدى FF هذه السمة في الواقع.
32 // لكن الكود أدناه سيضبطه على التحميل).
33 // إذا فشل التحميل، قم بالخروج.
34 إذا ((_currentLoadingReference.readyState != 'محمل') &&
35 (_currentLoadingReference.readyState != 'مكتمل')) {
36 عودة؛
37 }
38 آخر {
39 // دخول هذا الفرع يدل على نجاح التحميل.
40
41 // إذا كان البرنامج النصي الحالي يحدد وظيفة onLoad.
42 إذا (_currentOnScriptLoad) {
43 // تم الاتصال به عبر التقييم (هنا المشكلة).
44 تقييم(_currentOnScriptLoad);
45 //اضبط على قيمة خالية لتحرير الموارد.
46 _currentOnScriptLoad = null;
47 }
48
49 // اضبط الأحداث ذات الصلة على قيمة خالية لضمان تحرير الموارد.
50 إذا (Sys.Runtime.get_hostType() != Sys.HostType.InternetExplorer) {
51 // إذا كان المتصفح الحالي ليس IE، فراجع الكود أدناه
52 // ستجد أن حدث التحميل محدد لـ <script />.
53 _currentLoadingReference.onload = null;
54 }
55 آخر {
56 // إذا كان IE، راجع الكود أدناه وستجد ذلك
57 // <script /> يحدد حدث onreadystatechange.
58 _currentLoadingReference.onreadystatechange = null;
59 }
60
61 //أخيرًا حرر مرجع <script /> الحالي.
62 _currentLoadingReference = null;
63}
64}
65
66 // إذا كان لا يزال هناك نصوص مفرغة.
67 إذا (_references.length) {
68 // قائمة الانتظار.
69 فار مرجع = _references.dequeue();
70 // إنشاء <script />
71 var scriptElement = document.createElement('script');
72 //قم بتعيين <script /> الحالي ووظيفة رد الاتصال الحالية للتحميل الناجح.
73 _currentLoadingReference = scriptElement;
74 _currentOnScriptLoad =reference.onscriptload;
75
76 إذا (Sys.Runtime.get_hostType()!= Sys.HostType.InternetExplorer) {
77 // إذا لم يكن IE، فقم بتعيين السمة جاهزة لـ <script />.
78 // واستخدم حدث التحميل.
79 scriptElement.readyState = 'محمل';
80 scriptElement.onload =loadReferences;
81 }
82 آخر {
83 // إذا كان IE، فاستخدم حدث onreadystatechange.
84 scriptElement.onreadystatechange =loadReferences;
85}
86 scriptElement.type = 'text/javascript';
87 scriptElement.src =reference.url;
88
89 // أضف <script /> إلى DOM
90 var headElement = document.getElementsByTagName('head')[0];
91 headElement.appendChild(scriptElement);
92
93 عودة؛
94}
95
96 // إذا وصل التنفيذ إلى هذه النقطة، فهذا يعني أنه تم تحميل كافة البرامج النصية.
97 // إذا تم تحديد وظيفة رد الاتصال التي يتم تنفيذها بعد تحميل كافة البرامج النصية،
98 // ثم قم بتنفيذ الموارد وتحريرها.
99 إذا (_completionCallback) {
100 varCompletionCallback = _completionCallback;
101 var callbackContext = _callbackContext;
102
103 _completionCallback = null;
104 _callbackContext = null;
105
106 CompleteCallback(callbackContext);
107 }
108
109 _references = null;
110 }
111}
112Sys.ScriptLoader.registerClass('Sys.ScriptLoader');
يمكن ملاحظة أن طريقة Sys.ScriptLoader لتحميل البرنامج النصي هي إضافة عناصر <script /> إلى <header /> بشكل تسلسلي من خلال التعليمات البرمجية. في الواقع، يتم استخدامه نادرًا جدًا في نظام أطلس.
في الواقع، كود Sys.ScriptLoader بسيط للغاية، ويبدو أن التعليقات التي أضفتها غير ضرورية. تجدر الإشارة إلى أنه يتم تحرير جميع الموارد قدر الإمكان. انتبه بشكل خاص إلى الكود الذي يبدأ من السطر 99. يستخدم نص if أولاً متغيرات مؤقتة للاحتفاظ بمتغيرين عالميين، ثم يطلق المتغيرات العامة. والغرض منه هو تجنب تسرب الذاكرة الناتج عن الاستثناءات التي يتم طرحها عند تنفيذ رد الاتصال المكتمل، حتى لو كان هناك احتمال واحد فقط من كل عشرة آلاف. كلما زاد عدد Javascript، كان من الأسهل التسبب في تسرب الذاكرة، ومن الأفضل الانتباه إلى هذه المشكلة عند كتابة كود JS.
بعد ذلك، اشرح المعلمة الأولى لطريقة التحميل، المراجع. اعتقدت في البداية أن هذه كانت مصفوفة من فئة Sys.Reference، لكنني وجدت أنها في الواقع مختلفة تمامًا. على أي حال، نلقي نظرة على رمز هذه الفئة.
1Sys.Reference = الدالة() {
2
3 فار _ مكون؛
4 فار _onload؛
5
6 this.get_component = function() {
7_مكون الإرجاع؛
8}
9 this.set_component = وظيفة(قيمة) {
10 _component = value;
11 }
12
13 this.get_onscriptload = function() {
14 العودة _onload؛
15}
16 this.set_onscriptload = وظيفة(قيمة) {
17 _onload = القيمة؛
18}
19
20 هذا.التخلص = وظيفة () {
21 _component = null;
إثنان وعشرون }
ثلاثة وعشرين
24 هذا.getDescriptor = وظيفة () {
25 var td = new Sys.TypeDescriptor();
26
27 td.addProperty('component', Object);
28 td.addProperty('onscriptload', String);
29 عودة TD؛
30}
31}
32Sys.Reference.registerSealedClass('Sys.Reference', null, Sys.ITypeDescriptorProvider, Sys.IDisposable);
33Sys.TypeDescriptor.addType('script', 'reference', Sys.Reference);
مع الاهتمام بكود فئة Sys.ScriptLoader، يمكننا أن نرى أن كل عنصر في المصفوفة المرجعية هو في الواقع مجرد "{ url : " http://www.sample.com/sample.js "، onscriptload : " تنبيه (1) "}" كائن النموذج. لكن هذا جيد، يمكنك بسهولة استخدام JSON لإنشاء مثل هذه المصفوفة.
في هذه المرحلة، أعتقد أنه يجب على الجميع التفكير في كيفية استخدام Sys.ScriptLoader لإنشاء شريط تقدم تحميل JS بسهولة. ولكن الآن بعد أن كتبته هنا، سأستمر في تنفيذه بطريقة بسيطة.
الأول هو ملف aspx.
1<%@ لغة الصفحة='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<script runat="server">
6
7</script>
8
9<html xmlns=" http://www.w3.org/1999/xhtml " >
10 <رئيس التشغيل = "الخادم">
11 <title>تحميل البرامج النصية</title>
12 <لغة سكريبت = "جافا سكريبت">
13 وظيفة تحميل ()
14 {
15 document.getElementById("bar").style.width = "0px";
16 var scripts = new Array();
17 لـ (var i = 0; i < 8; i++)
18 {
19 var s = new Object();
20 var Sleep = Math.round((Math.random() * 400)) + 100;
21 s.url = "Script.ashx?sleep=" + Sleep + "&t=" + Math.random();
22 ثانية التكلفة = النوم؛
23 scripts.push(s);
أربعة وعشرون }
25
26 Jeffz.Sample.LoadScripts.load(scripts);
27}
28 </script>
29</الرأس>
30<body style="font-family: Arial;">
31 <form id="form1" runat="server">
32 <ديف>
33 <atlas:ScriptManager ID="ScriptManager1" runat="server">
34 <مخطوطات>
35 <atlas:ScriptReference Path="js/LoadScripts.js" />
36 </مخطوطات>
37 </atlas:ScriptManager>
38
39 شريط التقدم:
40 <div style="border: Solid 1px black;">
41 <div id="bar" style="height: 20px; width:0%; لون الخلفية:أحمر;"></div>
42 </ديف>
43 <نوع الإدخال = "زر" عند النقر = "تحميل ()" قيمة = "تحميل" />
44 <div id="message"></div>
45 </ديف>
46 </النموذج>
47</الجسم>
48</html>
بسيط جدا. يتم إنشاء أبسط شريط تقدم باستخدام عنصري DIV. يتم استدعاء الدالة Load() عند النقر فوق الزر. تقوم هذه الوظيفة بإنشاء روابط البرامج النصية بشكل عشوائي وإنشاء مجموعة برامج نصية مكونة من 8 عناصر. تنسيق مجموعة البرامج النصية كما يلي:
1var scripts =
2[
3 { عنوان URL : " http://www.sample.com/sample1.js "، التكلفة : costOfLoading1 }،
4 { رابط: " http://www.sample.com/sample2.js "، التكلفة: costOfLoading2 }،
5 { رابط: " http://www.sample.com/sample3.js "، التكلفة: costOfLoading3 }
6]؛
وغني عن القول أن سمة عنوان url لكل عنصر، ووظيفة التكلفة هي تمثيل قيمة الوقت المستغرق في تحميل الملف. هذه القيمة ليس لها وحدة، يتم فقط استخدام نسبة هذه القيمة في إجمالي الاستهلاك. بالإضافة إلى ذلك، يمكنك أن ترى أن هناك Script.ashx، والذي يستخدم لمحاكاة تحميل البرنامج النصي الطويل، وسوف يقوم بوضع السكون في مؤشر الترابط لفترة من الوقت بناءً على قيمة السكون في سلسلة الاستعلام (كما هو الحال في t التالي، الغرض فقط هو تجنب النقر فوق الزر عن طريق تغيير ذاكرة التخزين المؤقت للمتصفح querystring)، لا يحتوي هذا الملف على أي تعليمات برمجية تقريبًا ويمكن رؤية تنفيذه في نموذج التنزيل. وأخيرًا، يتم تحميله عن طريق استدعاء الأسلوب Jeffz.Sample.LoadScripts.load، والذي يتضمن التعليمات البرمجية التالية، LoadScripts.js:
1Type.registerNamespace('Jeffz.Sample');
2
3Jeffz.Sample.LoadScripts = وظيفة جديدة ()
4 {
5 فار TotalCost = 0;
6 var scriptLoader = new Sys.ScriptLoader();
7
8 هذا التحميل = الوظيفة (البرامج النصية)
9 {
10 إذا (Jeffz.Sample.__onScriptLoad != null)
11 {
12 رمي خطأ جديد("قيد التقدم");
13}
14
15 التكلفة الإجمالية = 0;
16 Jeffz.Sample.__onScriptLoad = onScriptLoad;
17 مراجع var = new Array();
18
19 var LoadCost = 0;
20 لـ (var i = 0; i < scripts.length; i++)
واحد وعشرون {
22 TotalCost += scripts[i].cost;
23 LoadCost += scripts[i].cost;
أربعة وعشرون
25 var ref = createReference(scripts[i].url, LoadCost);
26
27 مراجع.push(ref);
28 }
29
30 scriptLoader.load(references, onComplete);
31}
32
33 وظيفة createReference(url,loadCost)
34 {
35 var ref = new Object();
36 ref.url = url;
37 ref.onscriptload = "Jeffz.Sample.__onScriptLoad('" + url + "', " + uploadCost + ")";
38 مرجع العودة؛
39 }
40
41 دالة مكتملة ()
42 {
43 Jeffz.Sample.__onScriptLoad = null;
44}
45
46 وظيفة onScriptLoad(url, LoadedCost)
47 {
48 فار التقدم = 100.0 * LoadCost / TotalCost؛
49 document.getElementById("bar").style.width =progress + "%";
50 document.getElementById("message").innerHTML += ("<strong>" + url + "</strong>" + " upload.<br />");
51 }
52}
للأسف، يبدو أنه ليست هناك حاجة لشرح الكود على الإطلاق. حتى الآن، تم إكمال شريط التقدم البسيط لتحميل البرنامج النصي، وهو أمر بسيط للغاية. يمكن تنزيل الكود بالضغط هنا، أو يمكن مشاهدة التأثير بالضغط هنا.
لكن هل هذه نهاية الأمر؟ في الواقع، أنا لست راضيًا جدًا عن هذا الحل، على الرغم من أنه يجب أن يكون كافيًا لمعظم المواقف. يمكنك ملاحظة أنني قمت بتطبيق Jeffz.Sample.LoadScripts كـ Singleton، أي أنه لا يوجد مثيل آخر مثله. وفي بداية طريقة التحميل، يتم الحكم على ما إذا كانت قيد التحميل. وإذا كان الأمر كذلك، فسيتم طرح استثناء. السبب المباشر لتحقيق مثل هذا التحميل "أحادي الترابط" هو أنه مقيد بتطبيق Sys.ScriptLoader.
الرجاء إلقاء نظرة على السطر 44 من التعليمات البرمجية Sys.ScriptLoader وهو يستخدم eval لإعادة الاتصال "الشرير" عند تحميل البرنامج النصي. هذا في الواقع تطبيق غير مريح للغاية للمطورين، بسبب التقييم، من المستحيل تمرير مرجع إلى وظيفة كوظيفة رد اتصال. الشيء الوحيد الذي يمكن فعله هو تمرير "الكود الجذري" إلى Sys.ScriptLoader كسلسلة. على الرغم من أنه لا يزال من الممكن تحقيق تحميل البرنامج النصي "المتزامن" من خلال Sys.ScriptLoader (بصراحة، على الأكثر يمكنك إنشاء قائمة انتظار مثل Sys.ScriptLoader)، فإن كمية التعليمات البرمجية ستزداد بشكل طبيعي، وسيزداد تعقيد التطوير أيضًا يزيد.
ومع ذلك، أعتقد أن تحميل البرنامج النصي "أحادي الترابط" يكفي لمعظم المواقف. وإذا كانت هناك بالفعل متطلبات "خاصة"، ألن يكون من السهل على غالبية المطورين إعادة كتابتها من خلال الإشارة إلى مثل هذا المثال الواضح لـ Sys.ScriptLoader؟
http://www.cnblogs.com/JeffreyZhao/archive/2006/09/13/502357.html