คอมพิวเตอร์ Windows อินเทอร์เน็ต

ตัวจับเวลาใน Javascript (setInterval, setTimeout) ตัวอย่างของฟังก์ชัน jQuery setTimeout () Javascript ป้องกันไม่ให้ตัวจับเวลาหลายตัวเรียกใช้ setinterval ในเวลาเดียวกัน

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

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

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

ดูการสาธิต

ไวยากรณ์

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

var timeoutID = window.setTimeout (ฟังก์ชัน,); var timeoutID = window.setTimeout (รหัส,);

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

setTimeout กับ window.setTimeout

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

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

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

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

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

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

ฟังก์ชั่นระเบิด () (แจ้งเตือน ("บูม!");) setTimeout (ระเบิด 2000);

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

var ระเบิด = ฟังก์ชั่น () (การแจ้งเตือน ("บูม!");); setTimeout (ระเบิด 2000);

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

setTimeout (ฟังก์ชัน () (การแจ้งเตือน ("บูม!");), 2000);

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

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

ส่งพารามิเตอร์ไปที่ setTimout

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

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

ฟังก์ชั่นทักทาย (ทักทาย) (console.log (ทักทาย);) ฟังก์ชั่น getRandom (arr) (กลับ arr;) var ทักทาย = ["สวัสดี", "Bonjour", "Guten Tag"], randomGreeting = getRandom (ทักทาย); setTimeout (ฟังก์ชัน () (ทักทาย (randomGreeting);), 1000);

ดูการสาธิต

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

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

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

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

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

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

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

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

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

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

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

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

setTimeout (person.introduction.bind (คน), 50);

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

ใช้ห้องสมุด

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

setTimeout ($. พร็อกซี่ (person.introduction, บุคคล), 50);

ดูการสาธิต

ปิดตัวจับเวลา

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

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

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

ดูตัวอย่าง

มาสรุปกัน

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

เป็นสิ่งสำคัญอย่างยิ่งที่จะต้องเข้าใจว่าตัวจับเวลา JavaScript ทำงานอย่างไร บ่อยครั้งที่พฤติกรรมของพวกเขาไม่ตรงกับการรับรู้โดยสัญชาตญาณของเราเกี่ยวกับมัลติเธรด และนี่เป็นเพราะความจริงที่ว่าพวกมันทำงานบนเธรดเดียวกัน มาดูฟังก์ชันสี่อย่างที่เราสามารถควบคุมตัวจับเวลาได้:

  • var id = setTimeout (fn, หน่วงเวลา); - สร้างตัวจับเวลาอย่างง่ายที่จะเรียกใช้ฟังก์ชันที่ระบุหลังจากหน่วงเวลาที่ระบุ ฟังก์ชันส่งคืน ID ที่ไม่ซ้ำซึ่งตัวจับเวลาสามารถหยุดชั่วคราวได้
  • var id = setInterval (fn, หน่วงเวลา); - คล้ายกับ setTimeout แต่เรียกใช้ฟังก์ชันอย่างต่อเนื่องตามช่วงเวลาที่กำหนด (จนกว่าจะหยุด)
  • clearInterval (id) ;, clearTimeout (id); - ยอมรับ ID ตัวจับเวลา (ส่งคืนโดยหนึ่งในฟังก์ชันที่อธิบายไว้ข้างต้น) และหยุดการดำเนินการของการโทรกลับ "a.
แนวคิดหลักที่ต้องพิจารณาคือไม่รับประกันความแม่นยำของระยะเวลาหน่วงของตัวจับเวลา ในการเริ่มต้น เบราว์เซอร์จะเรียกใช้เหตุการณ์ JavaScript แบบอะซิงโครนัสทั้งหมดบนเธรดเดียวกัน (เช่น การคลิกเมาส์หรือตัวจับเวลา) และเฉพาะเมื่อเหตุการณ์ถึงคราวเดียวกัน นี่คือภาพประกอบที่ดีที่สุดโดยไดอะแกรมต่อไปนี้:

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

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

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

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

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

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

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

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

มาดูตัวอย่างที่แสดงให้เห็นความแตกต่างระหว่าง setTimeout และ setInterval กัน
setTimeout (ฟังก์ชัน () (/ * บล็อกยาวของรหัส ... * / setTimeout (arguments.callee, 10);), 10); setInterval (ฟังก์ชัน () (/ * บล็อกยาวของรหัส ... * /), 10);
ทั้งสองตัวเลือกนี้เทียบเท่ากันในแวบแรก แต่ในความเป็นจริงแล้วไม่เป็นเช่นนั้น โค้ดที่ใช้ setTimeout จะมีความล่าช้าอย่างน้อย 10 มิลลิวินาทีหลังจากการโทรครั้งก่อนเสมอ (อาจมากกว่านั้นได้ แต่จะไม่มีวันลดลง) ในขณะที่โค้ดที่ใช้ setInterval มักจะถูกเรียกทุกๆ 10 มิลลิวินาทีโดยไม่คำนึงว่าการโทรครั้งก่อนจะถูกดำเนินการเมื่อใด

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

ทั้งหมดนี้เป็นข้อมูลที่สำคัญอย่างยิ่งต่อการพัฒนา การรู้ว่ากลไก JavaScript ทำงานอย่างไร โดยเฉพาะอย่างยิ่งกับเหตุการณ์แบบอะซิงโครนัสจำนวนมาก (ซึ่งมักเกิดขึ้น) จะเป็นการวางรากฐานที่ยอดเยี่ยมสำหรับการสร้างแอปพลิเคชันขั้นสูง

  • จาก:
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497

หัวข้อ: SetTimeOut และ SetInterval ไหนดีกว่าที่จะใช้ใน JavaScript?

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

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

var d1 = วันที่ใหม่ (), d2 = วันที่ใหม่ (); setInterval (ฟังก์ชัน () (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, apt. 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497

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

setInterval (ฟังก์ชัน () (document.body.innerHTML = Math.random ();), 500);

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

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

3 ตอบโดย PunBB

  • จาก: มอสโก, Sovkhoznay 3, apt. 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497

Re: SetTimeOut กับ SetInterval แบบไหนดีกว่ากันใน JavaScript?

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

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

/ ** แทน: var timerId = setInterval (ฟังก์ชัน () (การแจ้งเตือน ("tick"), 2000); * / var timerId = setTimeout (ติ๊กฟังก์ชัน () (การแจ้งเตือน ("tick"); timerId = setTimeout (ขีด, 2000);), 2000);

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

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

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

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

4 ตอบโดย PunBB

  • จาก: มอสโก, Sovkhoznay 3, apt. 98
  • ลงทะเบียน: 2014.07.08
  • กระทู้: 3,896
  • ชอบ: 497

Re: SetTimeOut กับ SetInterval แบบไหนดีกว่ากันใน JavaScript?

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

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

var i = 1; setInterval (ฟังก์ชัน () (ฟังก์ชัน (i);), 100);

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

var i = 1; setTimeout (เรียกใช้ฟังก์ชัน () (func (i); setTimeout (เรียกใช้ 100);), 100);

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

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

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

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

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

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

5 ตอบโดย รุ่นพี่

  • จาก: เยรูซาเลม
  • ลงทะเบียน: 2015.06.02
  • กระทู้: 958
  • ชอบ: 274

Re: SetTimeOut กับ SetInterval แบบไหนดีกว่ากันใน JavaScript?

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

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

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

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

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

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

setTimeout

ไวยากรณ์:

var timerId = setTimeout (ฟังก์ชัน / รหัส, หน่วงเวลา [, arg1, arg2 ...])

ตัวเลือก:

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

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

ฟังก์ชั่น func ()(การแจ้งเตือน ("สวัสดี");) setTimeout (func, 1000);

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

นั่นคือบันทึกดังกล่าวทำงานในลักษณะเดียวกันทุกประการ:

SetTimeout ("การแจ้งเตือน (" สวัสดี ")", 1000);

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

ตั้งค่าหมดเวลา ( การทำงาน ()(แจ้งเตือน ("สวัสดี")), 1,000);

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

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

ตัวอย่างด้านล่างจะแสดง "Hi, I'm Vasya" ทุกที่ยกเว้น IE9-:

ฟังก์ชั่นบอกว่าสวัสดี (ใคร)(การแจ้งเตือน ("สวัสดีฉันคือ" + ใคร);) setTimeout (sayHi, 1000, "Vasya");

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

ฟังก์ชั่นบอกว่าสวัสดี (ใคร)(การแจ้งเตือน ("สวัสดี ฉัน" + ใคร);) setTimeout ( การทำงาน ()(สวัสดี ("วาสยา")), 1,000);

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

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

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

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

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

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

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

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

ฟังก์ชัน ผู้ใช้ (id)(นี้ .id = id นี้ .sayHi = การทำงาน ()(แจ้งเตือน (.id นี้);); ) var user = ผู้ใช้ใหม่ (12345); setTimeout ( การทำงาน ()(user.sayHi ();), 1,000);

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

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

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

ไวยากรณ์:

ClearTimeout (ตัวจับเวลา)

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

var timerId = setTimeout ( การทำงาน ()(การแจ้งเตือน (1)), 1,000); clearTimeout (timerId);

setInterval

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

var timerId = setInterval (ฟังก์ชัน / รหัส, หน่วงเวลา [, arg1, arg2 ...])

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

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

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

<ประเภทอินพุต = "ปุ่ม" onclick = "clearInterval (ตัวจับเวลา)" ค่า = "(! LANG: หยุด" > !} <สคริปต์> var i = 1; ตัวจับเวลา var = setInterval ( การทำงาน ()(แจ้งเตือน (i ++)), 2000);สคริปต์>

การเข้าคิวและการวางซ้อนการโทรใน setInterval

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

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

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

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

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

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

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

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

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

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

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

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

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

การเรียก setInterval (ฟังก์ชัน, การหน่วงเวลา) ไม่ได้รับประกันความล่าช้าที่แท้จริงระหว่างการดำเนินการ

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

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

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

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

<ประเภทอินพุต = "ปุ่ม" onclick = "clearTimeout (ตัวจับเวลา)" ค่า = "(! LANG: หยุด" > !} <สคริปต์> var i = 1; ตัวจับเวลา var = setTimeout ( เรียกใช้ฟังก์ชัน ()(การแจ้งเตือน (i ++); ตัวจับเวลา = setTimeout (เรียกใช้ 2000);), 2000);สคริปต์>

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

ตัวจับเวลาขั้นต่ำล่าช้า

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

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

พฤติกรรมของ setTimeout และ setInterval ที่มีความหน่วงเป็นศูนย์เป็นค่าเฉพาะของเบราว์เซอร์

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

ความถี่ตอบสนองที่แท้จริง

ทริกเกอร์ได้ไม่บ่อยนัก ในบางกรณี การหน่วงเวลาอาจไม่ใช่ 4ms แต่ 30ms หรือ 1000ms

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

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

สรุป: คุณควรได้รับคำแนะนำจากความถี่ 4ms แต่คุณไม่ควรไว้วางใจ

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

var timeMark = วันที่ใหม่; setTimeout ( ฟังก์ชั่นไป ()(var diff = ใหม่ วันที่ - timeMark; // พิมพ์การหน่วงเวลาอื่นไปยังคอนโซลแทนหน้าคอนโซล .log (แตกต่าง); //จำเวลาที่ลงท้ายได้ // เพื่อวัดการหน่วงเวลาที่แน่นอนระหว่างการโทร timeMark = วันที่ใหม่; setTimeout (ไป 100); ), 100 );

เคล็ดลับ setTimeout (func, 0)

เคล็ดลับนี้มีค่าควรแก่การเข้าสู่ประวัติของการแฮ็ก JavaScript

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

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

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

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

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

รวม

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

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

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

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

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

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

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

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

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

  1. ผม = 1;
  2. เลื่อนการเพิ่มหมายเลข "1" ลงในช่องป้อนข้อมูล 0.9 วินาที
  3. โดยทันทีหลังจากตั้งค่าปัญหานี้แล้ว วงจรจะดำเนินต่อไป: i = 2;
  4. เลื่อนการเพิ่มหมายเลข "2" ลงในช่องป้อนข้อมูล 0.9 วินาที

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

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

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

และอีกตัวแปรหนึ่ง ผมจะต้องเริ่มต้นนอกฟังก์ชัน - ตัวอย่างเช่นเช่นนี้:

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

ฟังก์ชัน besttest () (window.i = 0 window.timer1 = window.setInterval ("draw ()", 400)) ฟังก์ชัน draw () (document.getElementById ("test3") ค่า + = ++ i ถ้า (i > = 9) clearInterval (window.timer1))

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

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

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

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

เมนูแบบดึงออกของเราเป็นแบบดึงออกจริงๆ (จากใต้ "ส่วนหัว"): มีช่องว่างระหว่างองค์ประกอบเพื่อดูว่าจะดึงออกมาอย่างไร โดยไม่คาดคิด ปรากฏว่าเราไม่สามารถออกจากรายการที่มีความยาวต่างกันได้อย่างราบรื่นเท่ากัน อาจเป็นเพราะประสิทธิภาพของคอมพิวเตอร์ต่ำ (AMD Athlon 999 MHz)

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

  1. เราตั้งเวลาทั้งหมดของ "ออกเดินทาง" เช่น 200 มิลลิวินาที
  2. หากรายการแบบเลื่อนลงมีความสูง 20 พิกเซล เห็นได้ชัดว่าเราสามารถเลื่อนลงมาหนึ่งพิกเซลในเวลา 10 มิลลิวินาที และใน 200 มิลลิวินาที รายการทั้งหมดจะรวบรวมข้อมูล
  3. หากเมนูแบบเลื่อนลงสูง 40px เพื่อให้พอดีพร้อมกัน เราต้องเลื่อนลงทีละพิกเซลใน 5 มิลลิวินาที

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

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

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

ตอนนี้รายการกำลังเปิดตัวไม่มากก็น้อย สำหรับช่วงเวลาที่ใกล้เคียงกันมากหรือน้อย ในหน้า setinterval.htm

และนี่คือ Bru-mustache:

ฟังก์ชัน slide_do (obj, maxtop, offset) (ถ้า (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 (ฟังก์ชัน () (slide_do (ts, maxtop, offset)), หน่วงเวลา)

ก่อนเริ่ม ให้คำนวณ maxtop และ offset เหล่านี้ทั้งหมด แล้ววางรายการไว้ที่ตำแหน่ง mintop ฟังก์ชัน "เบื้องต้น" ทำอะไร สไลด์ ()ขนาด 40 เส้น และรวมกันทั้งหมด - ในไฟล์ setinterval.js ใช่ และอึนี้จะไม่ทำงานหากไม่มีสไตล์ชีตที่รวมอยู่