คอมพิวเตอร์ หน้าต่าง อินเทอร์เน็ต

ทำซ้ำการกระทำในช่วงเวลาจาวาสคริปต์ที่ระบุ ตัวอย่างฟังก์ชัน jQuery setTimeout() setTimeout โดยมีความล่าช้าเป็นศูนย์

  • จาก:
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497
หัวข้อ: SetTimeOut และ SetInterval อันไหนดีกว่าที่จะใช้ใน JavaScript?

ฟังก์ชัน setInterval ได้รับการออกแบบมาเพื่อเรียกใช้โค้ดหลายครั้งในช่วงเวลาปกติ อย่างไรก็ตาม มันมีข้อเสียหลายประการ โดยส่วนใหญ่จะมีลักษณะการทำงานที่แตกต่างกันในเบราว์เซอร์ที่แตกต่างกัน

ความแตกต่างประการแรกคือความแตกต่างในเวลาที่ตั้งเวลาไว้สำหรับการเปิดตัวครั้งถัดไป มาสร้างการทดสอบเล็กๆ กัน: เราจะวัดระยะเวลาที่ผ่านไปตั้งแต่เริ่มการวิ่งครั้งก่อนและตั้งแต่สิ้นสุดการวิ่งครั้งก่อน

var d1 = วันที่ใหม่ (), d2 = วันที่ใหม่ (); setInterval(function() ( var d = new Date(); document.body.innerHTML += (d - d1) + " " + (d - d2) + "
"; // ใส่เครื่องหมายไว้ที่จุดเริ่มต้นของฟังก์ชัน d1 = new Date(); while (new Date() - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

ผลลัพธ์จะเป็นข้อมูลเริ่มต้นจากบรรทัดที่สอง

ใน Firefox, Opera, Safari และ Chrome สถานการณ์จะคล้ายกัน: ตัวเลขแรกจะประมาณเท่ากับ 1,000 ตัวเลขที่สอง - น้อยกว่า 200 ความแตกต่างเพียงอย่างเดียวคือการแพร่กระจายของค่านิยม ความแตกต่างที่เล็กที่สุดคือใน Chrome และ Opera

2 ตอบกลับ โดย PunBB (แก้ไขโดย PunBB 2017.06.08 16:45)
  • จาก: มอสโก, Sovkhoznay 3, อพาร์ทเมนท์ 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497

ความแตกต่างอีกประการหนึ่งที่เห็นได้ชัดเจนน้อยกว่าและทำซ้ำได้ยากกว่า แต่บางครั้งอาจทำให้เกิดปัญหามากมายได้ คือการต้านทานต่อการเปลี่ยนแปลงเวลาของระบบ หากคุณรันการทดสอบต่อไปนี้

setInterval(function() ( document.body.innerHTML = Math.random(); ), 500);

และหลังจากเริ่มต้น ให้ตั้งเวลาของระบบย้อนกลับไปหนึ่งนาที จากนั้นการเปลี่ยนแปลงตัวเลขจะหยุดชั่วคราวในเบราว์เซอร์ Firefox และ Safari และหลังจากนั้นหนึ่งนาทีจะเริ่มอีกครั้ง แน่นอนว่าการแปลเวลาของระบบด้วยตนเองเป็นสถานการณ์ที่หายากมาก แต่หลายระบบได้รับการกำหนดค่าให้ซิงโครไนซ์เวลากับเซิร์ฟเวอร์บนอินเทอร์เน็ตโดยอัตโนมัติ ดังนั้นในบางสถานการณ์จึงไม่สามารถลดปัจจัยนี้ลงได้

ข้อเสียเล็กๆ อีกประการหนึ่งของฟังก์ชัน setInterval คือเพื่อให้สามารถหยุดการทำงานของมันได้ คุณต้องจำตัวระบุไว้ที่ใดที่หนึ่งซึ่งไม่สะดวกเสมอไป

3 ตอบกลับโดย PunBB
  • จาก: มอสโก, Sovkhoznay 3, อพาร์ทเมนท์ 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497
Re: SetTimeOut และ SetInterval อันไหนดีกว่าที่จะใช้ใน JavaScript?

หากต้องการกำจัดข้อเสียที่ระบุไว้ของ setInterval คุณสามารถใช้ setTimeout หลายรายการได้

ทางเลือกที่สำคัญสำหรับ setInterval คือ setTimeout แบบเรียกซ้ำ:

/** แทน: var timerId = setInterval(function() ( alert("tick"); ), 2000); */ var timerId = setTimeout(function ติ๊ก() ( alert("tick"); timerId = setTimeout(tick, 2000); ), 2000);

ในโค้ดด้านบน การดำเนินการครั้งต่อไปจะถูกกำหนดเวลาทันทีหลังจากที่การดำเนินการก่อนหน้าเสร็จสิ้น

setTimeout แบบเรียกซ้ำเป็นวิธีการกำหนดเวลาที่ยืดหยุ่นกว่า setInterval เนื่องจากสามารถกำหนดเวลาจนถึงการดำเนินการครั้งถัดไปได้แตกต่างกัน ขึ้นอยู่กับผลลัพธ์ของการดำเนินการปัจจุบัน

ตัวอย่างเช่น เรามีบริการที่สำรวจเซิร์ฟเวอร์เพื่อหาข้อมูลใหม่ทุกๆ 5 วินาที หากเซิร์ฟเวอร์โอเวอร์โหลด คุณสามารถเพิ่มช่วงเวลาการโพลเป็น 10, 20, 60 วินาที... จากนั้นจึงคืนกลับมาเมื่อทุกอย่างกลับสู่ปกติ

หากเรารันงานที่ต้องใช้ CPU เป็นประจำ เราก็จะสามารถประมาณเวลาที่ใช้ในการดำเนินการและวางแผนการทำงานครั้งต่อไปไม่ช้าก็เร็วได้

4 ตอบกลับโดย PunBB
  • จาก: มอสโก, Sovkhoznay 3, อพาร์ทเมนท์ 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497
Re: SetTimeOut และ SetInterval อันไหนดีกว่าที่จะใช้ใน JavaScript?

setTimeout แบบเรียกซ้ำรับประกันการหยุดชั่วคราวระหว่างการโทร ส่วน setInterval จะไม่รับประกัน

ลองเปรียบเทียบทั้งสองรหัส อันแรกใช้ setInterval:

วาร์ i = 1; setInterval(ฟังก์ชั่น() ( func(i); ), 100);

อันที่สองใช้ setTimeout แบบเรียกซ้ำ:

วาร์ i = 1; setTimeout(ฟังก์ชัน รัน() ( func(i); setTimeout(รัน, 100); ), 100);

ด้วย setInterval ตัวจับเวลาภายในจะเริ่มทำงานทุกๆ 100 มิลลิวินาทีและเรียกใช้ func(i):

การหยุดชั่วคราวจริงระหว่างการโทร func ด้วย setInterval น้อยกว่าที่ระบุไว้ในโค้ด!

นี่เป็นเรื่องปกติเนื่องจากเวลาในการทำงานของฟังก์ชั่นไม่ได้ถูกนำมาพิจารณา แต่อย่างใด มัน "กิน" ส่วนหนึ่งของช่วงเวลา

อาจเป็นไปได้ว่า func กลายเป็นเรื่องที่ซับซ้อนมากกว่าที่เราคาดไว้และใช้เวลาดำเนินการนานกว่า 100 มิลลิวินาที

ในกรณีนี้ ล่ามจะรอให้ฟังก์ชันเสร็จสิ้น จากนั้นตรวจสอบตัวจับเวลา และหากถึงเวลา (หรือผ่านไป) สำหรับการเรียก setInterval แล้ว การโทรครั้งถัดไปจะเกิดขึ้นทันที

หากฟังก์ชันทำงานนานกว่าการหยุดชั่วคราว setInterval การโทรจะเกิดขึ้นโดยไม่มีการหยุดชะงักใดๆ เลย

5 ตอบกลับโดย รุ่นพี่
  • จาก: กรุงเยรูซาเล็ม
  • ลงทะเบียน: 2015.06.02
  • กระทู้: 958
  • ชอบ: 274
Re: SetTimeOut และ SetInterval อันไหนดีกว่าที่จะใช้ใน JavaScript?

ทุกอย่างขึ้นอยู่กับงานที่ทำอยู่ เริ่มแรก SetTimeOut ใช้เพื่อเริ่มจับเวลาหนึ่งครั้ง และ SetInterval ใช้เพื่อเริ่มการวนซ้ำ แต่ฟังก์ชันทั้งสองสามารถใช้เพื่อเรียกใช้สคริปต์แบบวนซ้ำได้ ตัวอย่างเช่น หากคุณเรียกใช้สคริปต์แบบวนซ้ำในฟังก์ชัน SetTimeOut สคริปต์ก็จะทำหน้าที่เกือบจะคล้ายกับ SetInterval

ข้อเสียของ SetInterval ในขณะนี้คือ มันไม่ได้คำนึงถึงเวลาดำเนินการของสคริปต์ (ฟังก์ชัน) เอง และหากคุณใช้มันสำหรับการสืบค้นจำนวนมาก ช่วงเวลาจะลดลงอย่างมาก และ อาจแตกต่างกันในเบราว์เซอร์ที่แตกต่างกัน

แต่ขอย้ำอีกครั้งว่า หากฟังก์ชันหรือคำขอถูกย่อให้เล็กสุด ผู้ใช้ก็ไม่น่าจะรู้สึกถึงความแตกต่าง
ดังนั้นจะใช้อะไรขึ้นอยู่กับทุกคนตัดสินใจเอง

การหมดเวลาของ JavaScript คือฟังก์ชันจาวาสคริปต์ดั้งเดิมที่เรียกใช้งานโค้ดหลังจากการหน่วงเวลาที่ระบุ (ในหน่วยมิลลิวินาที) สิ่งนี้มีประโยชน์เมื่อคุณต้องการแสดงป๊อปอัปหลังจากที่ผู้ใช้ใช้เวลาบนเพจของคุณมาระยะหนึ่งแล้ว หรือคุณต้องการให้เอฟเฟกต์เมื่อคุณวางเมาส์เหนือองค์ประกอบเพื่อเริ่มต้นหลังจากผ่านไประยะหนึ่งแล้วเท่านั้น? ด้วยวิธีนี้ คุณสามารถหลีกเลี่ยงการกระตุ้นเอฟเฟกต์โดยไม่ได้ตั้งใจ หากผู้ใช้เลื่อนเมาส์ไปเหนือเอฟเฟกต์โดยไม่ได้ตั้งใจ

ตัวอย่าง setTimeout อย่างง่าย

เพื่อสาธิตวิธีการทำงานของฟีเจอร์นี้ ฉันขอแนะนำให้ดูการสาธิตต่อไปนี้ ซึ่งหน้าต่างป๊อปอัปจะปรากฏขึ้นสองวินาทีหลังจากคลิกปุ่ม

ดูการสาธิต

ไวยากรณ์

เอกสารประกอบ MDN จัดเตรียมไวยากรณ์ต่อไปนี้สำหรับ setTimeout:

var timeoutID = window.setTimeout(func, ); var timeoutID = window.setTimeout(รหัส, );

  • timeoutID – รหัสตัวเลขที่สามารถใช้ร่วมกับ clearTimeout() เพื่อปิดใช้งานตัวจับเวลา
  • func - ฟังก์ชั่นที่จะดำเนินการ;
  • code (ในรูปแบบทางเลือก) – บรรทัดของโค้ดที่จะดำเนินการ
  • ความล่าช้า – ระยะเวลาของความล่าช้าในหน่วยมิลลิวินาที หลังจากนั้นฟังก์ชันจะถูกเปิดใช้งาน ค่าเริ่มต้นคือ 0
setTimeout กับ window.setTimeout

ไวยากรณ์ข้างต้นใช้ window.setTimeout ทำไม

อันที่จริง setTimeout และ window.setTimeout เป็นฟังก์ชันเดียวกันในทางปฏิบัติ ข้อแตกต่างเพียงอย่างเดียวคือในนิพจน์ที่สองเราใช้เมธอด setTimeout เป็นคุณสมบัติของอ็อบเจ็กต์หน้าต่างส่วนกลาง

โดยส่วนตัวแล้ว ฉันคิดว่านี่ทำให้โค้ดซับซ้อนมากขึ้น หากเราต้องกำหนดวิธีการหมดเวลา JavaScript ทางเลือกที่สามารถพบได้และส่งคืนตามลำดับความสำคัญ เราจะพบปัญหามากยิ่งขึ้น

ในบทช่วยสอนนี้ ฉันไม่ต้องการยุ่งกับวัตถุหน้าต่าง แต่โดยทั่วไป มันขึ้นอยู่กับคุณที่จะตัดสินใจว่าจะใช้ไวยากรณ์ใด

ตัวอย่างการใช้งาน

นี่อาจเป็นชื่อของฟังก์ชัน:

ฟังก์ชั่น explode())( alert("บูม!"); ) setTimeout(ระเบิด, 2000);

ตัวแปรที่อ้างอิงถึงฟังก์ชัน:

var explode = function())( alert("บูม!"); ); setTimeout (ระเบิด, 2000);

หรือฟังก์ชันที่ไม่ระบุชื่อ:

setTimeout(function())( alert("บูม!"); ), 2000);

  • รหัสดังกล่าวมีความเข้าใจไม่ดี ดังนั้นจึงเป็นการยากที่จะปรับปรุงหรือแก้ไขจุดบกพร่อง
  • มันเกี่ยวข้องกับการใช้เมธอด eval() ซึ่งอาจเป็นช่องโหว่ที่อาจเกิดขึ้นได้
  • วิธีนี้จะช้ากว่าวิธีอื่นเนื่องจากต้องใช้ตัวแปล JavaScript

โปรดทราบว่าเรากำลังใช้วิธีการแจ้งเตือนการหมดเวลาของ JavaScript เพื่อทดสอบโค้ด

กำลังส่งพารามิเตอร์ไปยัง setTimout

ในตัวเลือกแรก (และข้ามเบราว์เซอร์) เราจะส่งพารามิเตอร์ไปยังฟังก์ชันโทรกลับ ซึ่งดำเนินการโดยใช้ setTimeout

ในตัวอย่างต่อไปนี้ เราแยกคำทักทายแบบสุ่มจากอาร์เรย์คำทักทายและส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชัน wait() ซึ่งดำเนินการโดย setTimeout โดยมีความล่าช้า 1 วินาที:

ฟังก์ชั่น ทักทาย(ทักทาย)( console.log(ทักทาย); ) ฟังก์ชั่น getRandom(arr)( กลับ arr; ) var ทักทาย = ["Hello", "Bonjour", "Guten Tag"], RandomGreeting = getRandom(ทักทาย); setTimeout(function())( ทักทาย(randomGreeting); ), 1,000);

ดูการสาธิต

วิธีการทางเลือก

ในไวยากรณ์ที่ให้ไว้ตอนต้นของบทความ มีวิธีอื่นที่คุณสามารถส่งพารามิเตอร์ไปยังฟังก์ชันเรียกกลับที่ดำเนินการโดยการหมดเวลาของ JavaScript วิธีการนี้แสดงถึงเอาท์พุตของพารามิเตอร์ทั้งหมดตามการหน่วงเวลา

จากตัวอย่างก่อนหน้านี้ เราได้รับ:

setTimeout (ทักทาย 1,000 สุ่มทักทาย);

วิธีนี้จะใช้งานไม่ได้ใน IE 9 และต่ำกว่า โดยที่พารามิเตอร์ที่ส่งผ่านจะถือว่าไม่ได้กำหนด แต่มีโพลีฟิลพิเศษบน MDN เพื่อแก้ไขปัญหานี้

ปัญหาที่เกี่ยวข้องและ “สิ่งนี้”

รหัสที่ดำเนินการโดย setTimeout ทำงานแยกจากฟังก์ชันที่เรียกมัน ด้วยเหตุนี้ เราจึงพบปัญหาบางอย่างที่สามารถแก้ไขได้โดยใช้คำสำคัญนี้

var person = ( firstName: "Jim",introduce: function())( console.log("Hi, I"m " + this.firstName); ) ); person.introduce(); // ผลลัพธ์: สวัสดี ฉัน " ม. จิม setTimeout(person.introduce, 50); // ผลลัพธ์: สวัสดี ฉันไม่ได้กำหนดไว้

เหตุผลสำหรับเอาต์พุตนี้คือในตัวอย่างแรกสิ่งนี้ชี้ไปที่วัตถุบุคคล และในตัวอย่างที่สองจะชี้ไปที่วัตถุหน้าต่างส่วนกลาง ซึ่งไม่มีคุณสมบัติชื่อ

เพื่อกำจัดความไม่สอดคล้องกันนี้ คุณสามารถใช้หลายวิธี:

บังคับให้ตั้งค่านี้

ซึ่งสามารถทำได้โดยใช้การผูก() ซึ่งเป็นวิธีการสร้างฟังก์ชันใหม่ที่เมื่อเรียกจะใช้ค่าเฉพาะเป็นค่าของคีย์นี้ ในกรณีของเรา วัตถุบุคคลที่ระบุ ในที่สุดสิ่งนี้ทำให้เรา:

setTimeout(person.introduce.bind(บุคคล), 50);

หมายเหตุ: วิธีการผูกถูกนำมาใช้ใน ECMAScript 5 ซึ่งหมายความว่าจะใช้ได้เฉพาะในเบราว์เซอร์รุ่นใหม่เท่านั้น ในกรณีอื่นๆ เมื่อคุณใช้งาน คุณจะได้รับข้อผิดพลาดในการเรียกใช้ JavaScript “ข้อผิดพลาดการหมดเวลาของฟังก์ชัน”

ใช้ห้องสมุด

ไลบรารีจำนวนมากมีฟังก์ชันในตัวที่จำเป็นในการแก้ปัญหานี้ ตัวอย่างเช่น jQuery.proxy() วิธีการ ใช้ฟังก์ชันและส่งกลับฟังก์ชันใหม่ซึ่งจะใช้บริบทเฉพาะเสมอ ในกรณีของเรา บริบทจะเป็น:

setTimeout($.proxy(person.introduce, person), 50);

ดูการสาธิต

ปิดการใช้งานตัวจับเวลา

ค่าที่ส่งคืนของ setTimeout คือรหัสตัวเลขที่สามารถใช้เพื่อปิดใช้งานตัวจับเวลาโดยใช้ฟังก์ชัน clearTimeout():

var timer = setTimeout (myFunction, 3000); clearTimeout (ตัวจับเวลา);

มาดูกันในการดำเนินการ ในตัวอย่างต่อไปนี้ หากคุณคลิกที่ปุ่ม "เริ่มนับถอยหลัง" การนับถอยหลังจะเริ่มต้นขึ้น หลังจากทำเสร็จแล้ว ลูกแมวก็จะได้รับของของตัวเอง แต่ถ้าคุณคลิกปุ่ม "หยุดการนับถอยหลัง" ตัวจับเวลาการหมดเวลาของ JavaScript จะหยุดและรีเซ็ต

ดูตัวอย่าง

มาสรุปกัน

setTimeout เป็นฟังก์ชันอะซิงโครนัส ซึ่งหมายความว่าการเรียกใช้ฟังก์ชันนี้จะเข้าสู่คิวและจะดำเนินการหลังจากการดำเนินการอื่นๆ ทั้งหมดในสแต็กเสร็จสิ้นแล้วเท่านั้น ไม่สามารถทำงานพร้อมกันกับฟังก์ชันอื่นหรือแยกเธรดได้

ที่มา: http://learn.javascript.ru/settimeout-setinterval

การใช้งาน JavaScript เกือบทั้งหมดมีตัวกำหนดเวลาภายในที่ช่วยให้คุณสามารถกำหนดเวลาฟังก์ชันที่จะเรียกใช้หลังจากระยะเวลาที่กำหนด

โดยเฉพาะอย่างยิ่ง คุณลักษณะนี้ได้รับการสนับสนุนในเบราว์เซอร์และในเซิร์ฟเวอร์ Node.JS

ตั้งค่าหมดเวลา

ไวยากรณ์:

var timerId = setTimeout (ฟังก์ชั่น/โค้ด, ดีเลย์ [, arg1, arg2...])

ตัวเลือก:

  • ฟังก์ชั่น/รหัส
    • ฟังก์ชันหรือบรรทัดโค้ดที่จะดำเนินการ
    • สตริงได้รับการเก็บรักษาไว้เพื่อความเข้ากันได้และไม่แนะนำ
  • ล่าช้า
    • เวลาแฝงเป็นมิลลิวินาที 1,000 มิลลิวินาทีเท่ากับ 1 วินาที
  • อาร์จี1 อาร์จี2…
    • อาร์กิวเมนต์ที่จะส่งผ่านไปยังฟังก์ชัน ไม่รองรับ IE9-
    • ฟังก์ชันจะถูกดำเนินการหลังจากเวลาที่ระบุไว้ในพารามิเตอร์การหน่วงเวลา

ตัวอย่างเช่น รหัสต่อไปนี้จะทริกเกอร์การแจ้งเตือน ("สวัสดี") หลังจากผ่านไปหนึ่งวินาที:

ฟังก์ชั่น func () ( alert("Hello" ); ) setTimeout(func, 1000 );

หากอาร์กิวเมนต์แรกเป็นสตริง ล่ามจะสร้างฟังก์ชันที่ไม่ระบุชื่อจากสตริงนั้น

นั่นคือรายการนี้ใช้งานได้เหมือนกันทุกประการ:

SetTimeout("alert("สวัสดี")" , 1000 );

ใช้ฟังก์ชันที่ไม่ระบุชื่อแทน:

SetTimeout(ฟังก์ชั่น () ( alert("Hello" ) ), 1000 );

พารามิเตอร์สำหรับฟังก์ชันและบริบท

ในเบราว์เซอร์สมัยใหม่ทั้งหมด รวมถึง IE10 setTimeout ช่วยให้คุณสามารถระบุพารามิเตอร์ของฟังก์ชันได้

ตัวอย่างด้านล่างจะแสดงคำว่า "สวัสดี ฉันชื่อวาสยา" ทุกที่ ยกเว้น IE9-:

ฟังก์ชั่น sayHi (ใคร) ( alert("Hello, I'm " + who); ) setTimeout(sayHi, 1,000 , "Vasya" );

...อย่างไรก็ตาม ในกรณีส่วนใหญ่ เราต้องการการสนับสนุนจาก IE เก่า และไม่อนุญาตให้คุณระบุอาร์กิวเมนต์ ดังนั้นเพื่อที่จะโอนสาย พวกเขาจึงปิดการโทรด้วยฟังก์ชันที่ไม่ระบุตัวตน:

ฟังก์ชั่น sayHi (ใคร) ( alert("สวัสดี ฉันชื่อ " + who); ) setTimeout(function () ( sayHi("Vasya") ), 1,000 );

การเรียก setTimeout ไม่ผ่านบริบทนี้

โดยเฉพาะอย่างยิ่ง การเรียกเมธอดอ็อบเจ็กต์ผ่าน setTimeout จะทำงานในบริบทระดับโลก ซึ่งอาจนำไปสู่ผลลัพธ์ที่ไม่ถูกต้อง

ตัวอย่างเช่น เรียก user.sayHi() หลังจากผ่านไปหนึ่งวินาที:

ฟังก์ชั่น ผู้ใช้ (id) ฟังก์ชั่น () ( การแจ้งเตือน(this .id); ); ) ผู้ใช้ var = ผู้ใช้ใหม่ (12345); setTimeout(user.sayHi, 1,000 ); // คาดว่าจะเป็น 12345 แต่จะส่งออกเป็น "ไม่ได้กำหนด"

เนื่องจาก setTimeout จะเรียกใช้ฟังก์ชัน user.sayHi ในบริบทส่วนกลาง จึงจะไม่สามารถเข้าถึงออบเจ็กต์ผ่านทางนี้

กล่าวอีกนัยหนึ่ง การเรียก setTimeout ทั้งสองนี้ทำสิ่งเดียวกัน:

// (1) หนึ่งบรรทัด setTimeout(user.sayHi, 1000 ); // (2) สิ่งเดียวกันในสองบรรทัด var func = user.sayHi; setTimeout(ฟังก์ชั่น, 1,000 );

โชคดีที่ปัญหานี้แก้ไขได้อย่างง่ายดายด้วยการสร้างฟังก์ชันระดับกลาง:

ผู้ใช้ฟังก์ชัน (id) ( this .id = id; this .sayHi = function () ( alert(this .id); ); ) var user = ผู้ใช้ใหม่ (12345); setTimeout(ฟังก์ชั่น () ( user.sayHi(); ), 1,000 );

ฟังก์ชั่น wrapper ใช้เพื่อส่งผ่านข้อโต้แย้งข้ามเบราว์เซอร์และรักษาบริบทการดำเนินการ

การยกเลิกการดำเนินการ

ฟังก์ชัน setTimeout จะส่งคืนรหัสจับเวลาที่สามารถใช้เพื่อยกเลิกการดำเนินการได้

ไวยากรณ์:

ล้างหมดเวลา (รหัสตัวจับเวลา)

ในตัวอย่างต่อไปนี้ เราตั้งค่าการหมดเวลาแล้วจึงลบ (เปลี่ยนใจ) เป็นผลให้ไม่มีอะไรเกิดขึ้น

var timerId = setTimeout(ฟังก์ชั่น () ( การแจ้งเตือน(1) ), 1,000 ); clearTimeout(รหัสตัวจับเวลา); ตั้งค่าช่วงเวลา

เมธอด setInterval มีไวยากรณ์คล้ายกับ setTimeout

var timerId = setInterval(func/code, Delay[, arg1, arg2...])

ความหมายของข้อโต้แย้งก็เหมือนกัน แต่ต่างจาก setTimeout ตรงที่มันไม่ได้รันฟังก์ชันนี้เพียงครั้งเดียว แต่จะทำซ้ำเป็นประจำตามช่วงเวลาที่กำหนด คุณสามารถหยุดการดำเนินการได้โดยการโทร:

ClearInterval(รหัสตัวจับเวลา)

ตัวอย่างต่อไปนี้ เมื่อรัน จะแสดงข้อความทุกสองวินาทีจนกว่าคุณจะคลิกที่ปุ่ม "หยุด":

วาร์ i = 1 ; var timer = setInterval(ฟังก์ชั่น () ( การแจ้งเตือน(i++) ), 2000 ); การเข้าคิวและการซ้อนทับการโทรใน setInterval

การเรียก setInterval(function, Delay) ทำให้ฟังก์ชันดำเนินการตามช่วงเวลาที่กำหนด แต่มีความละเอียดอ่อนที่นี่

ที่จริงแล้วการหยุดชั่วคราวระหว่างการโทรจะน้อยกว่าช่วงเวลาที่กำหนด

ตัวอย่างเช่น ลองใช้ setInterval(function() ( func(i++) ), 100) กัน มันดำเนินการ func ทุก ๆ 100ms โดยเพิ่มตัวนับในแต่ละครั้ง

ในภาพด้านล่าง บล็อกสีแดงคือเวลาดำเนินการของ func เวลาระหว่างบล็อกคือเวลาระหว่างการทำงานของฟังก์ชันและน้อยกว่าค่าดีเลย์ที่ตั้งไว้!

นั่นคือเบราว์เซอร์จะเริ่มต้นการเปิดใช้งานฟังก์ชันอย่างเรียบร้อยทุกๆ 100 มิลลิวินาที โดยไม่คำนึงถึงเวลาดำเนินการของฟังก์ชันนั้นเอง

มันเกิดขึ้นที่การทำงานของฟังก์ชันใช้เวลานานกว่าความล่าช้า ตัวอย่างเช่น ฟังก์ชันมีความซับซ้อน แต่ความล่าช้ามีน้อย หรือฟังก์ชันประกอบด้วยข้อความแจ้งเตือน / ยืนยัน / พร้อมท์ที่บล็อกเธรดการดำเนินการ นี่คือสิ่งที่เริ่มน่าสนใจ

หากไม่สามารถเปิดใช้งานฟังก์ชันได้เนื่องจากเบราว์เซอร์ไม่ว่าง ฟังก์ชันนั้นจะถูกจัดคิวและดำเนินการทันทีที่เบราว์เซอร์ว่าง

รูปภาพด้านล่างแสดงให้เห็นว่าเกิดอะไรขึ้นกับฟังก์ชันที่ใช้เวลานานในการดำเนินการ

การเรียกใช้ฟังก์ชันที่เริ่มต้นโดย setInterval จะถูกเพิ่มลงในคิวและเกิดขึ้นทันทีเมื่อเป็นไปได้:

การเปิดตัวฟังก์ชันครั้งที่สองจะเกิดขึ้นทันทีหลังจากสิ้นสุดฟังก์ชันแรก:

การดำเนินการไม่ถูกจัดคิวมากกว่าหนึ่งครั้ง

หากฟังก์ชันใช้เวลาดำเนินการนานกว่าการดำเนินการตามกำหนดการหลายครั้ง ฟังก์ชันนั้นจะยังคงอยู่ในคิวหนึ่งครั้ง จึงไม่เกิดการ “สะสม” ของการเปิดตัว

ในภาพด้านล่าง setInterval พยายามเรียกใช้ฟังก์ชันใน 200ms และจัดคิวการโทร ที่ 300ms และ 400ms ตัวจับเวลาจะกลับมาทำงานอีกครั้ง แต่ไม่มีอะไรเกิดขึ้น

การเรียก setInterval(function, Delay) ไม่รับประกันความล่าช้าจริงระหว่างการประมวลผล

มีหลายกรณีที่ความล่าช้าที่เกิดขึ้นจริงมากกว่าหรือน้อยกว่าที่ระบุไว้ โดยทั่วไปแล้ว อย่างน้อยก็ไม่ใช่ความจริงที่ว่าจะมีความล่าช้าบ้าง

ทำซ้ำ setTimeout ที่ซ้อนกัน

ในกรณีที่ไม่จำเป็นต้องทำซ้ำเป็นประจำ แต่จำเป็นต้องมีการหน่วงเวลาระหว่างการรัน setTimeout จะถูกใช้เพื่อตั้งค่าใหม่ทุกครั้งที่เรียกใช้ฟังก์ชัน

ด้านล่างนี้เป็นตัวอย่างที่แจ้งเตือนโดยมีช่วงเวลา 2 วินาทีระหว่างกัน

วาร์ i = 1 ; var timer = setTimeout(ฟังก์ชันรัน () ( แจ้งเตือน(i++); timer = setTimeout(รัน, 2000 ); ), 2000 );

เส้นเวลาการดำเนินการจะมีความล่าช้าคงที่ระหว่างการวิ่ง ภาพประกอบสำหรับความล่าช้า 100ms:

ความล่าช้าในการจับเวลาขั้นต่ำ

ตัวจับเวลาของเบราว์เซอร์มีเวลาแฝงต่ำที่สุดเท่าที่จะเป็นไปได้ มันแตกต่างกันไปจากประมาณศูนย์ถึง 4ms ในเบราว์เซอร์สมัยใหม่ ในรุ่นเก่าอาจนานกว่าและถึง 15ms

ตามมาตรฐาน ความล่าช้าขั้นต่ำคือ 4ms ดังนั้นจึงไม่มีความแตกต่างระหว่าง setTimeout(..,1) และ setTimeout(..,4)

ลักษณะการทำงานแบบไม่มีเวลาในการตอบสนองของ setTimeout และ setInterval เป็นแบบเฉพาะเบราว์เซอร์

  • ใน Opera setTimeout(.., 0) จะเหมือนกับ setTimeout(.., 4) มันถูกดำเนินการน้อยกว่า setTimeout(.. ,2) นี่คือคุณสมบัติของเบราว์เซอร์นี้
  • ใน Internet Explorer การตั้งค่าความล่าช้าเป็นศูนย์ setInterval(.., 0) จะไม่ทำงาน สิ่งนี้ใช้เฉพาะกับ setInterval เช่น setTimeout(.., 0) ทำงานได้ดี
  • ความถี่ทริกเกอร์จริง

    การทริกเกอร์อาจเกิดขึ้นน้อยกว่ามาก ในบางกรณี ความล่าช้าอาจไม่ใช่ 4ms แต่เป็น 30ms หรือแม้แต่ 1,000ms

    เบราว์เซอร์ส่วนใหญ่ (เดสก์ท็อปเป็นหลัก) ยังคงดำเนินการ setTimeout / setInterval แม้ว่าแท็บจะไม่ได้ใช้งานก็ตาม ในเวลาเดียวกันจำนวนหนึ่ง (Chrome, FF, IE10) ลดความถี่ตัวจับเวลาขั้นต่ำเป็น 1 ครั้งต่อวินาที ปรากฎว่าตัวจับเวลาจะทำงานในแท็บ "พื้นหลัง" แต่ไม่ค่อยมี

    เมื่อทำงานโดยใช้พลังงานแบตเตอรี่ บนแล็ปท็อป เบราว์เซอร์ยังสามารถลดความถี่ในการรันโค้ดให้น้อยลงและประหยัดพลังงานแบตเตอรี่ IE มีชื่อเสียงเป็นพิเศษในเรื่องนี้ การลดลงสามารถทำได้หลายครั้ง ขึ้นอยู่กับการตั้งค่า หากโหลด CPU สูงเกินไป JavaScript อาจไม่สามารถประมวลผลตัวจับเวลาได้ทันเวลา การดำเนินการนี้จะข้ามการรัน setInterval บางรายการ

    สรุป: ความถี่ 4ms นั้นคุ้มค่าที่จะเน้น แต่คุณไม่ควรเชื่อใจมัน

    ส่งออกช่วงเวลาไปยังคอนโซล รหัสที่นับช่วงเวลาระหว่างการโทรมีลักษณะดังนี้:

    var timeMark = วันที่ใหม่; setTimeout(function go () ( var diff = new Date - timeMark; // พิมพ์การหน่วงเวลาถัดไปไปยังคอนโซลแทนคอนโซลหน้า .log(diff); // จดจำเวลาที่ส่วนท้ายสุด // เพื่อวัด ความล่าช้าระหว่างการโทร timeMark = new Date ; setTimeout(go, 100 ); ), 100 ); เคล็ดลับคือ setTimeout(func, 0)

    เคล็ดลับนี้สมควรที่จะเข้าสู่พงศาวดารของการแฮ็ก JavaScript

    ฟังก์ชันนี้รวมอยู่ใน setTimeout(func, 0) หากคุณต้องการเรียกใช้หลังจากสิ้นสุดสคริปต์ปัจจุบัน

    ประเด็นก็คือ setTimeout จะไม่เรียกใช้ฟังก์ชันทันที เขาเพียงวางแผนการดำเนินการเท่านั้น แต่ล่าม JavaScript จะเริ่มดำเนินการฟังก์ชั่นที่วางแผนไว้หลังจากเรียกใช้สคริปต์ปัจจุบันเท่านั้น

    ตามมาตรฐาน setTimeout ไม่สามารถเรียกใช้ฟังก์ชันที่มีความล่าช้าเป็น 0 ได้ ดังที่เราได้กล่าวไว้ก่อนหน้านี้ ความล่าช้ามักจะเป็น 4ms แต่สิ่งสำคัญที่นี่คือการดำเนินการไม่ว่าในกรณีใดจะเกิดขึ้นหลังจากการเรียกใช้โค้ดปัจจุบัน

    ตัวอย่างเช่น:

    ผลลัพธ์ var; ฟังก์ชั่น showResult () ( การแจ้งเตือน (ผลลัพธ์); ) setTimeout (showResult, 0 ); ผลลัพธ์ = 2 *2 ; // จะส่งออกทั้งหมด 4 รายการ

    เมธอด setInterval(func, ดีเลย์) และ setTimeout(func, ดีเลย์) ช่วยให้คุณสามารถรัน func เป็นประจำ/หนึ่งครั้งทุกๆ มิลลิวินาทีที่ล่าช้า

    ทั้งสองวิธีส่งคืนรหัสตัวจับเวลา ใช้เพื่อหยุดการดำเนินการโดยการเรียก clearInterval / clearTimeout

    | | ตั้งค่าช่วง | ตั้งค่าหมดเวลา | || ----------- | ---------- | | เวลา | การโทรเป็นไปตามตัวจับเวลาอย่างเคร่งครัด หากล่ามไม่ว่าง สายหนึ่งจะถูกเข้าคิว เวลาดำเนินการฟังก์ชันจะไม่ถูกนำมาพิจารณา ดังนั้นช่วงเวลาตั้งแต่สิ้นสุดการรันครั้งหนึ่งจนถึงจุดเริ่มต้นของอีกรันหนึ่งอาจแตกต่างกัน | การเรียกแบบเรียกซ้ำไปยัง setTimeout จะถูกใช้แทน setInterval ซึ่งจำเป็นต้องมีการหยุดชั่วคราวระหว่างการดำเนินการ | | ล่าช้า | ความล่าช้าขั้นต่ำ: 4ms | ความล่าช้าขั้นต่ำ: 4ms | | คุณสมบัติเบราว์เซอร์ | Latency 0 ไม่ทำงานใน IE | ใน Opera เวลาแฝงเป็นศูนย์จะเทียบเท่ากับ 4ms และความล่าช้าอื่นๆ จะได้รับการจัดการอย่างถูกต้อง รวมถึง 1ms, 2ms และ 3ms ที่ไม่ได้มาตรฐาน |

    เมธอด setInterval() ที่นำเสนอบนอินเทอร์เฟซ Window และ Worker จะเรียกใช้ฟังก์ชันซ้ำๆ หรือดำเนินการข้อมูลโค้ด โดยมีการหน่วงเวลาคงที่ระหว่างการโทรแต่ละครั้ง โดยจะส่งคืน ID ช่วงเวลาซึ่งระบุช่วงเวลาโดยไม่ซ้ำกัน ดังนั้นคุณจึงสามารถลบออกได้ในภายหลังโดยการเรียก clearInterval() วิธีการนี้ถูกกำหนดโดยมิกซ์In WindowOrWorkerGlobalScope

    ไวยากรณ์ var ช่วงเวลา ID = ขอบเขต.setInterval( ฟังก์ชั่น, ล่าช้า, [หาเรื่อง1, หาเรื่อง2, ...]); var ช่วงเวลา ID = ขอบเขต.setInterval( รหัส, ล่าช้า); พารามิเตอร์ func ฟังก์ชันที่จะดำเนินการทุกๆ มิลลิวินาทีที่มีการหน่วงเวลา ฟังก์ชันไม่ผ่านอาร์กิวเมนต์ใดๆ และไม่ต้องการค่าส่งคืน รหัส ไวยากรณ์ทางเลือกช่วยให้คุณสามารถรวมสตริงแทนฟังก์ชัน ซึ่งจะถูกคอมไพล์และดำเนินการทุกๆ มิลลิวินาทีที่มีการหน่วงเวลา ไวยากรณ์นี้คือ ไม่แนะนำด้วยเหตุผลเดียวกันกับที่ทำให้การใช้ eval() มีความเสี่ยงด้านความปลอดภัย ล่าช้า เวลาในหน่วยมิลลิวินาที (หนึ่งในพันของวินาที) ตัวจับเวลาควรหน่วงเวลาระหว่างการดำเนินการของฟังก์ชันหรือโค้ดที่ระบุ ดูรายละเอียดด้านล่างเกี่ยวกับช่วงค่าการหน่วงเวลาที่อนุญาต arg1, ..., argN ตัวเลือก อาร์กิวเมนต์เพิ่มเติมที่ถูกส่งผ่านไปยังฟังก์ชันที่ระบุโดย ฟังก์ชั่นเมื่อตัวจับเวลาหมดลง

    หมายเหตุ : การส่งผ่านอาร์กิวเมนต์เพิ่มเติมไปยัง setInterval() ในรูปแบบแรกจะไม่ทำงานใน Internet Explorer 9 และรุ่นก่อนหน้า หากคุณต้องการเปิดใช้งานฟังก์ชันนี้บนเบราว์เซอร์นั้น คุณต้องใช้โพลีฟิล (ดูหัวข้อ)

    ส่งคืนค่า

    IntervalID ที่ส่งคืนเป็นค่าตัวเลขที่ไม่ใช่ศูนย์ ซึ่งระบุตัวจับเวลาที่สร้างขึ้นโดยการเรียกไปยัง setInterval() ; ค่านี้สามารถส่งผ่านเพื่อยกเลิกการหมดเวลาได้

    อาจเป็นประโยชน์หากทราบว่า setInterval() และ setTimeout() ใช้กลุ่ม ID เดียวกัน และ clearInterval() และ clearTimeout() ในทางเทคนิคสามารถใช้สลับกันได้ อย่างไรก็ตาม เพื่อความชัดเจน คุณควรพยายามจับคู่พวกมันเสมอเพื่อหลีกเลี่ยงความสับสนเมื่อดูแลรักษาโค้ดของคุณ

    หมายเหตุ: อาร์กิวเมนต์ความล่าช้าจะถูกแปลงเป็นจำนวนเต็ม 32 บิตที่ลงนาม วิธีนี้จะจำกัดความล่าช้าอย่างมีประสิทธิภาพไว้ที่ 2147483647 ms เนื่องจากระบุเป็นจำนวนเต็มที่ลงนามใน IDL

    ตัวอย่างที่ 1: ไวยากรณ์พื้นฐาน

    ตัวอย่างต่อไปนี้แสดงให้เห็นถึงไวยากรณ์พื้นฐานของ setInterval()

    Var IntervalID = window.setInterval(myCallback, 500, "พารามิเตอร์ 1", "พารามิเตอร์ 2"); ฟังก์ชั่น myCallback(a, b) ( // รหัสของคุณที่นี่ // พารามิเตอร์เป็นทางเลือกล้วนๆ console.log(a); console.log(b); )

    ตัวอย่างที่ 2: การสลับสองสี

    ตัวอย่างต่อไปนี้เรียกใช้ฟังก์ชัน flashtext() หนึ่งครั้งต่อวินาทีจนกระทั่งกดปุ่ม Stop

    ตัวอย่าง setInterval/clearInterval var nIntervId; ฟังก์ชั่น changeColor() ( nIntervId = setInterval(flashText, 1000); ) ฟังก์ชั่น flashText() ( var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "red" ? " blue" : "red"; // oElem.style.color == "red" ? "blue" : "red" เป็นตัวดำเนินการแบบไตรภาค ) ฟังก์ชั่น stopTextColor() ( clearInterval(nIntervId); )

    สวัสดีชาวโลก

    หยุด

    ตัวอย่างที่ 3: การจำลองเครื่องพิมพ์ดีด

    ตัวอย่างต่อไปนี้จำลองเครื่องพิมพ์ดีดโดยการล้างข้อมูลในขั้นแรก จากนั้นค่อยๆ พิมพ์เนื้อหาลงใน NodeList ที่ตรงกับกลุ่มตัวเลือกที่ระบุ

    เครื่องพิมพ์ดีด JavaScript - MDN ตัวอย่างฟังก์ชันเครื่องพิมพ์ดีด (sSelector, nRate) ( ฟังก์ชั่น clean () ( clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; ) ฟังก์ชั่นเลื่อน (oSheet, nPos , bEraseAndStop) ( if (!oSheet.hasOwnProperty("parts") || aMap.length< nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap < oSheet.parts.length) { oRel = oSheet.parts]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets, 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts); this.parts = new Sheet(this.parts); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = , aMap = ; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems)); /* Uncomment the following line if you have previously hidden your elements via CSS: */ // aItems.style.visibility = "visible"; } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets, 0, false)); clean(); }; } /* usage: */ var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */ var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */ // oTWExample2.rate = 150; onload = function () { oTWExample1.play(); oTWExample2.play(); }; span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline; } #info { width: 180px; height: 150px; float: right; background-color: #eeeeff; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px; /* visibility: hidden; */ }

    CopyLeft 2012 โดย Mozilla Developer Network

    [ เล่น | หยุดชั่วคราว | ยุติ ]

    Vivamus blandit Massa ut metus mattis ใน fringilla lectus imperdiet Proin ac ante a felis ornare vehicula Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim ที่ lacus ultricies vitae facilisis nisi fringilla ในความไม่ชัดเจน tincidunt tincidunt เครื่องพิมพ์ดีดจาวาสคริปต์

    Lorem ipsum dolor นั่ง amet, consectetur adipiscing elit. นัลลัม อุลตริซ โดเลอร์ เอซี โดเลอร์ อิมเพอร์ไดเอท อุลแลมคอร์เปอร์ Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna Quisque ใน ante tellus ใน placerat est ถิ่นที่อยู่อาศัย Pellentesque morbi tristique senectus และ netus และ malesuada ชื่อเสียง ac turpis egestas Donec a mi magna, quis mattis dolor. Etiam นั่ง amet ligula quis urna auctor imperdiet nec faucibus ante. มอริส เวล คอนเซกเตตูร์ โดลอร์ Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, ไม่ใช่ viverra justo diam eget arcu Phasellus adipiscing fermentum nibh ac commodo น้ำ turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.

    Phasellus ac nisl lorem:
    Nullam commodo suscipit lacus ไม่ใช่ aliquet Phasellus ac nisl lorem, sed facilisis ligula น้ำ cursus lobortis placerat Sed dui nisi, elementum eu sodales ac, placerat นั่ง amet mauris Pellentesque dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat และ ultrices tortor sodales ไม่ใช่ Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget Praesent scelerisque urna vitae nibh tristique varius consequat neque luctus. จำนวนเต็ม ornare, erat a porta tempus, velit justo fermentum elit, a fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue utmassa ประเสนต์ วีเต อีรอส เอรัต, ปุลวินาร์ ลาโอเรต มากนา. Maecenas ขนถ่าย mollis nunc ในตำแหน่ง Pellentesque นั่ง amet metus turpis lobortis tempor eu vel tortor Cras sodales eleifend interdum.

    Duis lobortis sapien quis nisl luctus porttitor. ในเวลาชั่วคราว semper libero, eu tincidunt dolor eleifend นั่ง amet. ไม่จำเป็นต้องคำนึงถึง rhoncus non non diam Morbi auctor ornare orci, ไม่ใช่ euismod felis gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dnissim est ในเวลาต่อมา Aliquam aliquam diam ไม่ใช่ felis convallis suscipit สิ่งอำนวยความสะดวก Nulla Donec lacus risus, dnissim และ fringilla et, egestas vel eros. Duis malesuada accumsan dui และ fringilla mauris bibStartum quis Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.

    Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus Proin Mattis lobortis lobortis Quisque accumsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor นั่ง amet, consectetur adipiscing elit. ไม่ต้องมีอิสระ nunc. Nullam tortor nunc, องค์ประกอบและ consectetur และ ultrices eu orci Lorem ipsum dolor นั่ง amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula estas.

    อาร์กิวเมนต์การโทรกลับ

    ตามที่กล่าวไว้ก่อนหน้านี้ Internet Explorer เวอร์ชัน 9 และต่ำกว่าไม่รองรับการส่งอาร์กิวเมนต์ไปยังฟังก์ชันการเรียกกลับใน setTimeout() หรือ setInterval() รหัสเฉพาะ IE ต่อไปนี้สาธิตวิธีการเอาชนะข้อจำกัดนี้ หากต้องการใช้ เพียงเพิ่มโค้ดต่อไปนี้ที่ด้านบนของสคริปต์ของคุณ

    /*\ |*| |*| โพลีฟิลเฉพาะของ IE ที่ช่วยให้สามารถส่งผ่านข้อโต้แย้งที่กำหนดเองไปยัง |*| ฟังก์ชั่นการโทรกลับของตัวจับเวลาจาวาสคริปต์ (ไวยากรณ์มาตรฐาน HTML5)..setInterval |*| https://site/User:fusionchess |*| |*| ไวยากรณ์: |*| var timeoutID = window.setTimeout(func, ล่าช้า [, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout (รหัส, ล่าช้า); |*| var IntervalID = window.setInterval(func, ดีเลย์ [, arg1, arg2, ...]); |*| var IntervalID = window.setInterval (รหัส, ล่าช้า); |*| \*/ if (document.all && !window.setTimeout.isPolyfill) ( var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, ฯลฯ */) ( var aArgs = Array .prototype.slice.call(อาร์กิวเมนต์, 2); return __nativeST__(vCallback instanceof Function ? function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay); ); window.setTimeout.isPolyfill = true; ) if (document.all && !window.setInterval.isPolyfill) ( var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, ฯลฯ */) ( var aArgs = Array.prototype. Slice.call(อาร์กิวเมนต์, 2); return __nativeSI__(vCallback instanceof Function ? function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay); ); window.setInterval.isPolyfill = true; )

    ความเป็นไปได้อีกอย่างหนึ่งคือการใช้ฟังก์ชันที่ไม่ระบุตัวตนเพื่อโทรกลับ แม้ว่าโซลูชันนี้จะมีราคาแพงกว่าเล็กน้อยก็ตาม ตัวอย่าง:

    Var IntervalID = setInterval(function() ( myFunc("one", "two", "three"); ), 1000); var IntervalID = setInterval(ฟังก์ชั่น(arg1) ().bind(ไม่ได้กำหนด, 10), 1,000);

    แท็บที่ไม่ใช้งานต้องใช้ Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2)

    เริ่มต้นใน Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) ช่วงเวลาจะถูกจำกัดให้เริ่มทำงานไม่บ่อยเกินหนึ่งครั้งต่อวินาทีในแท็บที่ไม่ได้ใช้งาน

    ปัญหา "นี้"

    เมื่อคุณส่งเมธอดไปที่ setInterval() หรือฟังก์ชันอื่นๆ ระบบจะเรียกใช้เมธอดนี้ด้วยค่าที่ไม่ถูกต้อง ปัญหานี้ได้รับการอธิบายโดยละเอียดในการอ้างอิง JavaScript

    คำอธิบาย

    โค้ดที่ดำเนินการโดย setInterval() ทำงานในบริบทการดำเนินการที่แยกจากฟังก์ชันที่ถูกเรียกใช้ ด้วยเหตุนี้ คีย์เวิร์ดนี้สำหรับฟังก์ชันที่เรียกจึงถูกตั้งค่าเป็นอ็อบเจ็กต์หน้าต่าง (หรือโกลบอล) ซึ่งไม่เหมือนกับค่านี้สำหรับฟังก์ชันที่เรียกว่า setTimeout ดูตัวอย่างต่อไปนี้ (ซึ่งใช้ setTimeout() แทน setInterval() - ที่จริงแล้วปัญหาจะเหมือนกันสำหรับตัวจับเวลาทั้งสองตัว):

    MyArray = ["ศูนย์", "หนึ่ง", "สอง"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); myArray.myMethod(); // พิมพ์ "ศูนย์, หนึ่ง, สอง" myArray.myMethod(1); // พิมพ์ "หนึ่ง" setTimeout(myArray.myMethod, 1000); // พิมพ์ "" หลังจาก 1 วินาที setTimeout(myArray.myMethod, 1500, "1"); // พิมพ์ "ไม่ได้กำหนด" หลังจาก 1.5 วินาที // ส่งวัตถุ "นี้" ด้วย .call จะไม่ทำงาน // เพราะสิ่งนี้จะเปลี่ยนค่าของสิ่งนี้ภายใน setTimeout เอง // ในขณะที่เราต้องการเปลี่ยนค่าของสิ่งนี้ภายใน myArray .myMethod // อันที่จริงแล้ว มันจะเป็นข้อผิดพลาดเนื่องจากโค้ด setTimeout คาดว่าสิ่งนี้จะเป็นวัตถุหน้าต่าง: setTimeout.call(myArray, myArray.myMethod, 2000); // ข้อผิดพลาด: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: การดำเนินการที่ผิดกฎหมายกับวัตถุต้นแบบ WrappedNative" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // ข้อผิดพลาดเดียวกัน

    ดังที่คุณเห็นแล้วว่าไม่มีวิธีใดในการส่งวัตถุนี้ไปยังฟังก์ชันการโทรกลับใน JavaScript ดั้งเดิม

    ทางออกที่เป็นไปได้

    วิธีที่เป็นไปได้ในการแก้ปัญหา "นี้" คือการแทนที่ฟังก์ชันโกลบอล setTimeout() หรือ setInterval() ดั้งเดิมสองตัวด้วยฟังก์ชันโกลบอลสองตัว ไม่ใช่คนพื้นเมืองรายการที่เปิดใช้งานการร้องขอผ่านเมธอด Function.prototype.call ตัวอย่างต่อไปนี้แสดงการแทนที่ที่เป็นไปได้:

    // เปิดใช้งานการผ่านวัตถุ "นี้" ผ่านทางตัวจับเวลา JavaScript var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2 ฯลฯ */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); ); window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2 ฯลฯ */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); );

    การแทนที่ทั้งสองนี้ยังเปิดใช้งานการผ่านอาร์กิวเมนต์มาตรฐาน HTML5 ไปยังฟังก์ชันการโทรกลับของตัวจับเวลาใน IE ดังนั้นจึงสามารถใช้เป็น ที่ไม่ได้มาตรฐานโพลีฟิลด้วย ดูสำหรับ เป็นไปตามมาตรฐานโพลีฟิล

    การทดสอบคุณสมบัติใหม่:

    MyArray = ["ศูนย์", "หนึ่ง", "สอง"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); setTimeout(แจ้งเตือน 15.00 "สวัสดีชาวโลก!"); // การใช้ setTimeout และ setInterval มาตรฐานจะยังคงอยู่ แต่... setTimeout.call(myArray, myArray.myMethod, 2000); // พิมพ์ "ศูนย์, หนึ่ง, สอง" หลังจากผ่านไป 2 วินาที setTimeout.call(myArray, myArray.myMethod, 2500, 2); // พิมพ์ "สอง" หลังจาก 2.5 วินาที

    สำหรับเวอร์ชันที่ซับซ้อนมากขึ้นแต่ยังคงเป็นแบบโมดูลาร์ ( ภูต) โปรดดูการจัดการ Daemons ของ JavaScript เวอร์ชันที่ซับซ้อนกว่านี้ไม่มีอะไรนอกจากคอลเลกชั่นวิธีการขนาดใหญ่และปรับขนาดได้สำหรับ ภูตตัวสร้าง อย่างไรก็ตาม ภูตตัวสร้างเองก็ไม่มีอะไรนอกจากการโคลนของ มินิเดมอนพร้อมการสนับสนุนเพิ่มเติมสำหรับ ในนั้นและ เริ่มต้นใหม่ฟังก์ชั่นที่ประกาศในระหว่างการสร้างอินสแตนซ์ของ ภูต. ดังนั้น มินิเดมอนเฟรมเวิร์กยังคงเป็นวิธีที่แนะนำสำหรับแอนิเมชั่นแบบธรรมดา เพราะ ภูตหากไม่มีการรวบรวมวิธีการต่าง ๆ ก็ถือเป็นการโคลนนิ่งของมัน

    minidamon.js /*\ |*| |*| :: MiniDaemon:: |*| |*| ฉบับแก้ไข #2 - 26 กันยายน 2014.setInterval |*| https://site/User:fusionchess |*| https://github.com/madmurphy/minidaemon.js |*| |*| เฟรมเวิร์กนี้เผยแพร่ภายใต้ GNU Lesser General Public License เวอร์ชัน 3 หรือใหม่กว่า |*| http://www.gnu.org/licenses/lgpl-3.0.html |*| \*/ ฟังก์ชั่น MiniDaemon (oOwner, fTask, nRate, nLen) ( if (!(สิ่งนี้ && อินสแตนซ์ของ MiniDaemon นี้)) ( return; ) if (arguments.length< 2) { throw new TypeError("MiniDaemon - not enough arguments"); } if (oOwner) { this.owner = oOwner; } this.task = fTask; if (isFinite(nRate) && nRate >0) ( this.rate = Math.floor(nRate); ) ถ้า (nLen > 0) ( this.length = Math.floor(nLen); ) ) MiniDaemon.prototype.owner = null; MiniDaemon.prototype.task = null; MiniDaemon.prototype.rate = 100; MiniDaemon.prototype.length = อนันต์; /* คุณสมบัติเหล่านี้ควรเป็นแบบอ่านอย่างเดียว */ MiniDaemon.prototype.SESSION = -1; MiniDaemon.prototype.INDEX = 0; MiniDaemon.prototype.PAUSED = จริง; MiniDaemon.prototype.BACKW = จริง; /* วิธีการทั่วโลก */ MiniDaemon.forceCall = ฟังก์ชั่น (oDmn) ( oDmn.INDEX += oDmn.BACKW ? -1: 1; if (oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn .BACKW) === false || oDmn.isAtEnd()) ( oDmn.pause(); return false; ) คืนค่า true; ); /* วิธีการอินสแตนซ์ */ MiniDaemon.prototype.isAtEnd = function () ( return this.BACKW ? isFinite(this.length) && this.INDEX< 1: this.INDEX + 1 >นี้.ความยาว; ); MiniDaemon.prototype.synchronize = function () ( ถ้า (this.PAUSED) ( return; ) clearInterval(this.SESSION); this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this); ); MiniDaemon.prototype.pause = ฟังก์ชั่น () ( clearInterval(this.SESSION); this.PAUSED = true; ); MiniDaemon.prototype.start = function (bReverse) ( var bBackw = Boolean(bReverse); if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) ( return; ) this.BACKW = bBackw; this.PAUSED = false; this.synchronize(); );

    MiniDaemon ส่งผ่านอาร์กิวเมนต์ไปยังฟังก์ชันโทรกลับ หากคุณต้องการทำงานกับเบราว์เซอร์ที่ไม่รองรับคุณสมบัตินี้โดยกำเนิด ให้ใช้วิธีใดวิธีหนึ่งที่เสนอข้างต้น

    ไวยากรณ์

    var myDaemon = MiniDaemon ใหม่ ( วัตถุนี้, โทรกลับ[ , ประเมิน [, ความยาว]]);

    คำอธิบาย บันทึกการใช้งาน

    ฟังก์ชัน setInterval() มักใช้เพื่อตั้งค่าการหน่วงเวลาสำหรับฟังก์ชันที่จะดำเนินการซ้ำแล้วซ้ำอีก เช่น ภาพเคลื่อนไหว คุณสามารถยกเลิกช่วงเวลาได้โดยใช้ WindowOrWorkerGlobalScope.clearInterval()

    หากคุณต้องการให้ฟังก์ชันของคุณถูกเรียกใช้ ครั้งหนึ่งหลังจากการหน่วงเวลาที่ระบุ ให้ใช้ .

    ข้อจำกัดความล่าช้า

    เป็นไปได้ที่ช่วงเวลาจะซ้อนกัน นั่นคือการเรียกกลับสำหรับ setInterval() สามารถเรียก setInterval() เพื่อเริ่มช่วงเวลาอื่นที่ทำงานอยู่ แม้ว่าช่วงแรกจะยังคงทำงานอยู่ก็ตาม เพื่อบรรเทาผลกระทบที่อาจเกิดขึ้นกับสิ่งนี้ ประสิทธิภาพ เมื่อช่วงเวลาซ้อนกันเกินกว่าห้าระดับ เบราว์เซอร์จะบังคับใช้ค่าขั้นต่ำ 4 ms สำหรับช่วงเวลาโดยอัตโนมัติ ความพยายามที่จะระบุค่าน้อยกว่า 4 ms ในการเรียก setInterval() ที่ซ้อนกันลึกจะถูกปักหมุดไว้ที่ 4 ms

    เบราว์เซอร์อาจบังคับใช้ค่าขั้นต่ำที่เข้มงวดยิ่งขึ้นสำหรับช่วงเวลาภายใต้สถานการณ์บางอย่าง แม้ว่าค่าเหล่านี้ไม่ควรเป็นเรื่องปกติก็ตาม โปรดทราบว่าระยะเวลาจริงที่ผ่านไประหว่างการโทรไปยังการโทรกลับอาจนานกว่าความล่าช้าที่กำหนด ดูสาเหตุของความล่าช้านานกว่าที่ระบุไว้ใน WindowOrWorkerGlobalScope.setTimeout() สำหรับตัวอย่าง

    ตรวจสอบให้แน่ใจว่าระยะเวลาการดำเนินการสั้นกว่าความถี่ของช่วงเวลา

    หากมีความเป็นไปได้ที่ตรรกะของคุณอาจใช้เวลาดำเนินการนานกว่าช่วงเวลา ขอแนะนำให้คุณเรียกใช้ฟังก์ชันที่มีชื่อซ้ำโดยใช้ setTimeout() ตัวอย่างเช่น หากใช้ setInterval() เพื่อสำรวจเซิร์ฟเวอร์ระยะไกลทุกๆ 5 วินาที เวลาแฝงของเครือข่าย เซิร์ฟเวอร์ที่ไม่ตอบสนอง และปัญหาอื่นๆ มากมายอาจทำให้คำขอไม่ดำเนินการให้เสร็จสิ้นภายในเวลาที่กำหนดได้ ด้วยเหตุนี้ คุณอาจพบว่าตัวเองมีคำขอ XHR ที่เข้าคิวซึ่งไม่จำเป็นต้องส่งคืนตามลำดับ

    ในการเขียนโปรแกรมในภาษาสคริปต์จำเป็นต้องสร้างการหยุดชั่วคราวเป็นระยะ - เพื่อหยุดการทำงานของโปรแกรมชั่วคราวจากนั้นจึงทำงานต่อไป ตัวอย่างเช่น ในสคริปต์ VBS และ PHP สามารถใช้วิธีการต่อไปนี้:

    VBS: wscript.sleep 1500 (หยุด 1.5 วินาที)

    PHP: นอน (10); (หยุดเป็นเวลา 10 วินาที)

    ในระหว่างการหยุดชั่วคราวดังกล่าว ระบบรันไทม์ (PHP หรือ VBS) ไม่ได้ทำอะไร. นักพัฒนาที่พยายามใช้สิ่งที่คล้ายกันใน Javascript อย่างสังหรณ์ใจจะต้องประหลาดใจอย่างไม่เป็นที่พอใจ ข้อผิดพลาดทั่วไปเมื่อพยายามสร้างการหยุดชั่วคราวใน Javascript มีลักษณะดังนี้:

    ฟังก์ชั่น badtest() ( for (var i=1; i< 10; i++) { window.setTimeout("document.getElementById("test1").value += " + i, 900) } }

    คุณคิดว่าเมื่อถึงคราววาดตัวเลขถัดไป setTimeout ของคุณจะหยุด Javascript ไม่ให้ทำงานโดยสุจริต รอ 0.9 วินาที เพิ่มตัวเลขที่ต้องการที่ส่วนท้ายของช่องป้อนข้อมูล จากนั้นจึงทำงานต่อ แต่ในความเป็นจริง สิ่งนี้ไม่เป็นความจริง: setInterval และ setTimeout ใน Javascript จะชะลอการดำเนินการ (หรือฟังก์ชัน) ที่ระบุในวงเล็บเท่านั้น ในตัวอย่างของเรา สิ่งต่อไปนี้จะเกิดขึ้น:

  • ฉัน = 1;
  • ชะลอการเพิ่มหมายเลข "1" ลงในช่องป้อนข้อมูล 0.9 วินาที
  • ทันทีหลังจากตั้งค่าปัญหานี้ วงจรจะดำเนินต่อไป: i=2;
  • ชะลอการเพิ่มหมายเลข "2" ลงในช่องป้อนข้อมูล 0.9 วินาที
  • ความหมายในทันที เช่น 1 ms (นั่นคือ มีขนาดเล็กอย่างไม่เป็นสัดส่วนเมื่อเทียบกับ 900 ms): ลูปจะทำงานเกือบจะในทันที โดยสร้างงานที่เลื่อนออกไปหลายงานจากจุดเดียวกันในเวลาเดียวกัน ซึ่งหมายความว่างาน "วาด" ที่ค้างอยู่ทั้งหมดจะเสร็จสิ้นในเวลาเดียวกันโดยไม่หยุดระหว่างการเพิ่มหมายเลขใหม่ วงจรเริ่มต้นขึ้น ทุกอย่างค้างเป็นเวลา 0.9 วินาที และ shirr - ตัวเลขทั้งหมดจะถูกยิงติดต่อกัน

    จะใช้ setTimeout อย่างถูกต้องในกรณีเช่นนี้ได้อย่างไร? มันซับซ้อน. คุณจะต้องเรียกใช้ฟังก์ชัน ซ้ำ ๆ(จากภายในฟังก์ชันจะมีฟังก์ชันเดียวกัน) และเพื่อให้กระบวนการนี้ไม่มีที่สิ้นสุด ให้กำหนดเงื่อนไขการหยุด (เช่น ขนาดของตัวเลขที่จะพิมพ์):

    ฟังก์ชั่น welltest() ( ถ้า (i< 9) { document.getElementById("test2").value += ++i window.setTimeout("welltest()", 400) } }

    และตัวแปรที่ฉันจะต้องเริ่มต้นได้ภายนอกฟังก์ชัน - ตัวอย่างเช่น:

    ตอนนี้ทุกอย่างทำงานได้ตามปกติ (เราลดเวลาหน่วงลงจาก 0.9 วินาทีเป็น 0.4 วินาที) แต่สำหรับงานดังกล่าว การใช้ setInterval แทนที่จะเป็น setTimeout มีเหตุผลมากกว่า (แม้ว่าจะต้องใช้สองฟังก์ชันก็ตาม):

    ฟังก์ชั่น besttest() ( window.i = 0 window.timer1 = window.setInterval("draw()", 400) ) function Draw() ( document.getElementById("test3").value += ++i if (i >= 9) clearInterval(window.timer1) )

    ลักษณะเฉพาะของเมธอด Javascirpt setInterval คือมันไม่ผ่าน "ด้วยตัวเอง" ต้องหยุดด้วยวิธี clearInterval พิเศษ และเพื่อให้ชัดเจนว่าควรหยุดอะไร งานสำหรับการดำเนินการที่เลื่อนออกไปจึงถูกกำหนดตัวระบุพิเศษ - ตัวจับเวลา: window.timer1 = window.setInterval(...)

    ตัวระบุยังสามารถกำหนดให้กับงานที่สร้างโดยเมธอด setTimeout ได้ รหัสตัวจับเวลาทั้งหมดจะต้องไม่ซ้ำกัน (ไม่ซ้ำกันภายในหน้าต่างเบราว์เซอร์ปัจจุบัน) จากนั้นคุณสามารถสร้างงานต่างๆ มากมายในหน้าต่างที่ใช้การดำเนินการแบบเลื่อนออกไป และงานเหล่านี้จะถูกดำเนินการแบบขนาน (พร้อมกัน หากคอมพิวเตอร์มีทรัพยากรเพียงพอ) ซึ่งโดยพื้นฐานแล้วเป็นไปไม่ได้ใน PHP หรือ VBS

    นี่คือตัวอย่างของเพจที่มีตัวจับเวลา Javascript หลายตัวทำงานพร้อมกัน: setinterval.htm (ฟังก์ชัน Javascript ในไฟล์ setinterval.js) ตัวจับเวลาหน้าทั้งหมด (ยกเว้นเมนู) สามารถหยุดได้โดยใช้ปุ่ม Esc ตัวจับเวลาตัวอย่างทั้งหมดจะขึ้นอยู่กับการนับถอยหลัง "ตามธรรมชาติ" (ไม่ใช่นามธรรม i++) - เวลาหรือระยะทาง “นาฬิกา” ทั้งหมดได้รับการยกเลิกการซิงโครไนซ์เป็นพิเศษ (เพื่อความชัดเจน) ตัวจับเวลาตามระยะทางจะใช้ใน "ตัวบ่งชี้" และในเมนูแบบเลื่อนลง ("ดึงออก")

    เมนูแบบเลื่อนลง

    เมนูแบบเลื่อนของเราเป็นแบบเลื่อนจริงๆ (จากใต้ “ส่วนหัว”): ช่องว่างจะถูกทิ้งไว้เป็นพิเศษระหว่างองค์ประกอบต่างๆ เพื่อให้คุณเห็นว่าเมนูเลื่อนออกไปอย่างไร ปรากฎว่าเราไม่สามารถทำให้ทางออกราบรื่นเท่ากันสำหรับรายการที่มีความยาวต่างกันได้ - อาจเนื่องมาจากประสิทธิภาพต่ำของคอมพิวเตอร์ (AMD Athlon 999 MHz)

    เห็นได้ชัดว่าเพื่อความสวยงามและความกลมกลืนจึงจำเป็นต้องมีรายการเมนูต่างๆ ปรากฏขึ้นพร้อมๆ กัน กล่าวคือ รายการที่ยาวควรเลื่อนออกด้วยความเร็วที่สูงกว่า และรายการที่สั้นลงด้วยความเร็วที่ต่ำกว่า ดูเหมือนว่าจะสามารถนำไปใช้ได้ดังนี้:

  • เราตั้งเวลา "ออกเดินทาง" ทั้งหมดเป็น 200 มิลลิวินาที
  • หากรายการแบบเลื่อนลงมีความสูง 20 px เห็นได้ชัดว่าเราสามารถเลื่อนลงได้หนึ่งพิกเซลต่อช่วงเวลา 10 มิลลิวินาที จากนั้นใน 200 มิลลิวินาที รายการทั้งหมดจะออกมา
  • หากดรอปดาวน์สูง 40px เพื่อให้พอดีกับระยะเวลาเท่ากัน เราจะต้องเลื่อนลงหนึ่งพิกเซลทุกๆ 5 มิลลิวินาที
  • ด้วยตรรกะนี้ หากรายการแบบเลื่อนลงสูง 200px เราควรเลื่อนลงหนึ่งพิกเซลทุกๆ 1 มิลลิวินาที แต่ความเร็วดังกล่าวใช้ไม่ได้บนคอมพิวเตอร์ของเรา - เบราว์เซอร์ไม่มีเวลาวาดตำแหน่งใหม่ของรายการในหนึ่งมิลลิวินาที ใช่. Javascript จัดการนับได้ (มีอะไรให้นับบ้าง) แต่เบราว์เซอร์ (Firefox) ไม่มีเวลาแสดง สถานการณ์ทั่วไปสำหรับเว็บ

    ดังนั้นจึงเป็นไปได้ที่จะทำให้เวลาในการออกจากเมนูเท่ากันไม่มากก็น้อยโดยใช้ไม้ค้ำยันเท่านั้นและยังไม่ชัดเจนว่าจะทำงานบนคอมพิวเตอร์ที่เร็วกว่าได้อย่างไร แต่เราควรนับอันที่ช้าที่สุดใช่ไหม? อัลกอริทึม (โดยไม่คำนึงถึงความเร็วของคอมพิวเตอร์) กลายเป็นดังนี้:

  • ตั้งเวลารวมในการตรวจสอบรายการ: เวลา = 224 (ms)
  • เรากำหนดเวลาขั้นต่ำสำหรับหนึ่งช่วงเวลาในรอบ: ความล่าช้า = 3 (ms)
  • กำหนดขั้นตอนขั้นต่ำสำหรับการย้ายรายการ: offset = 1 (px)
  • เราเปลี่ยนแปลงทั้งหมดนี้ขึ้นอยู่กับความสูงของรายการ: 1) เพิ่มเวลาล่าช้า (ช่วงเวลา) ในสัดส่วนผกผันกับความสูงและเป็นสัดส่วนโดยตรงกับเวลาทั้งหมด (ที่ความสูง 224 ค่าสัมประสิทธิ์คือ 1) 2) หากความสูงมากกว่า 40 px ให้เพิ่มขั้นขั้นต่ำตามสัดส่วนความสูง ได้รับค่าคงที่ "40" จากการทดลองสำหรับคอมพิวเตอร์ที่ช้าที่สุด การทดสอบบนคอมพิวเตอร์ Pentium 4 CPU 2.53GHz เผยให้เห็นตัวเลขเดียวกันทุกประการ - 40 มิฉะนั้นตัวจับเวลาจะไม่เรียงลำดับรายการจะไม่เป็นไปตามขั้นตอน
  • ตอนนี้รายการออกมาไม่มากก็น้อย ในช่วงเวลาใกล้เคียงกันไม่มากก็น้อย บนหน้า setinterval.htm

    และนี่คือบรูซ:

    ฟังก์ชั่น slide_do(obj, maxtop, offset) ( if (getTopLeft(obj).top< maxtop) { obj.style.top = getTopLeft(obj).top + offset } else { if (obj && obj.timer1) { clearInterval(obj.timer1) obj.timer1 = null } } }

    ตัวฟังก์ชันเองซึ่งผลักรายการที่ซ้อนกันออกจากเมนูนั้น อย่างที่เราเห็นนั้นง่ายมาก สิ่งที่เหลืออยู่คือการรันด้วยบรรทัดนี้:

    Ts.timer1 = setInterval(function())(slide_do(ts, maxtop, offset)), ล่าช้า)

    ก่อนที่จะเริ่มต้น เพียงคำนวณแม็กซ์ท็อปและออฟเซ็ตเหล่านี้ทั้งหมด และวางรายการในตำแหน่งมินท็อปด้วย นี่คือสิ่งที่ฟังก์ชัน “เบื้องต้น” สไลด์() ของ 40 บรรทัดทำ และทั้งหมดรวมกัน - ในไฟล์ setinterval.js ใช่ และเรื่องไร้สาระนี้จะใช้งานไม่ได้เลยหากไม่มีไฟล์สไตล์ที่รวมไว้