ทำไม setTimeout () ทำให้แอปของฉันล้าสมัย แต่ตัวจับเวลา Rxjs () สมัครสมาชิก (…) ไม่ได้?


9

ฉันมีองค์ประกอบที่ "ขี้เกียจโหลด" ความคิดเห็นบางอย่างในช่วงเวลา 100ms

เมื่อฉันใช้ setTimeout มันล้าหลังจริงๆ

ส่วนประกอบ

<div *ngFor="let post of posts">
   <app-post [post]="post" ></app-post>
</div>

สิ่งนี้ทำให้แอปพลิเคชันของฉันล้าหลัง (avg fps 14, เวลาว่าง 51100ms):

while(this.postService.hasPosts()){
  setTimeout(()=> {
   this.posts.push(this.postService.next(10));
  },100);
}

ทำให้แอปพลิเคชันของฉันราบรื่น (เฉลี่ย 35 fps, เวลาว่าง 40800ms)

while(this.postService.hasPosts()){
  timer(100).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}

มีคำอธิบายใด ๆ ทำไมตัวจับเวลา rxjs ถึงใช้งานได้ดีกว่ามาก?

ฉันทำการวิเคราะห์ runtime ด้วย firefox ในตัวอย่างแรกอัตราเฟรมลดลงถึง 14 fps ในอีกตัวอย่างหนึ่ง 35 fps

แม้เวลาว่างจะลดลง 20%

วิธีนี้ราบรื่นยิ่งขึ้น (เฉลี่ยต่อวินาที 45, ไม่ได้ใช้งานเวลา 13500ms):

interval(100).pipe(takeWhile(this.postService.hasPosts()).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}

คำตอบ:


2

ทางออกสุดท้ายของคุณคือทางออกเดียวที่ถูกต้อง

อีกสองวิธีไม่ควรทำงานอย่างที่คุณคาดหวังไว้ ที่จริงแล้วควรส่งผลให้เกิดการวนซ้ำไม่สิ้นสุด

นี่เป็นเพราะการใช้งานEventloopของ JavaScript รูปภาพต่อไปนี้แสดงรูปแบบของ JavaScript รันไทม์ (ภาพนี้ถ่ายจากที่นี่ ):

ป้อนคำอธิบายรูปภาพที่นี่

ส่วนที่เกี่ยวข้องสำหรับเราเป็นและstack queueรันไทม์ JavaScript queueประมวลผลข้อความบนนั้น แต่ละข้อความจะเชื่อมโยงกับฟังก์ชั่นที่เรียกว่าเป็นข้อความที่ถูกประมวลผล

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

ตอนนี้ถ้าสแต็คว่างเปล่า JavaScript จะประมวลผลข้อความถัดไปในqueue(เก่าที่สุด)

ถ้าคุณใช้setTimeout(() => doSomething(),100)ที่doSomething()ฟังก์ชั่นได้รับการเพิ่มลงในคิวหลังจาก 100 มิลลิวินาที นี่คือเหตุผลที่ 100 มิลลิวินาทีไม่ใช่เวลารับประกัน แต่เวลาน้อยที่สุด ดังนั้นคุณdoSomething methodจะได้รับการเรียกเท่านั้นหากกองว่างเปล่าและไม่มีอะไรอยู่ในคิว

แต่ในขณะที่คุณวนซ้ำในขณะที่ลูปและเงื่อนไขของคุณขึ้นอยู่กับโค้ดภายในของsetTimeoutคุณคุณได้สร้างลูปไม่สิ้นสุดเนื่องจากสแต็กจะไม่ว่างเปล่าและดังนั้นthis.posts.push(this.postService.next(10));โค้ดของคุณจะไม่ถูกเรียก

สำหรับการปรับใช้ RxJS จะเป็นจริง พวกเขาใช้ schedulers เพื่อจัดการเวลา มีการใช้งานตัวกำหนดตารางเวลาภายในที่แตกต่างกันใน RxJS แต่อย่างที่เราเห็นในการนำไปใช้งานintervalและtimerหากเราไม่ได้ระบุตัวกำหนดตารางเวลาค่าเริ่มต้นคือ asyncScheduler asyncScheduler กำหนดการทำงานกับsetIntervalที่ทำงานเหมือนที่setTimeoutกล่าวไว้ข้างต้นและผลักดันข้อความอื่นในคิว

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.