Chrome: หมดเวลา / ช่วงเวลาถูกระงับในแท็บพื้นหลัง?


130

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

ดูเหมือนว่า Chrome จะระงับหรืออย่างน้อยก็ชะลอการเรียกใช้จาวาสคริปต์ในแท็บที่ไม่มีโฟกัส ไม่สามารถหาข้อมูลเกี่ยวกับเรื่องนี้ได้มากนัก หมายความว่าเราไม่สามารถรันงานเบื้องหลังได้เช่นการตรวจสอบเป็นระยะ ๆ บนเซิร์ฟเวอร์โดยใช้การเรียก XHR และsetInterval(ฉันสงสัยว่าจะเห็นพฤติกรรมเดียวกันsetIntervalนี้จะเขียนการทดสอบถ้ามีเวลาอยู่กับฉัน)

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


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

@gAMBOOKa: ลองดูคำตอบของ @ pimvdb มีแนวโน้มว่าจะช้าลงสูงสุดหนึ่งครั้งต่อวินาที
KooiInc

4 ปีต่อมาและปัญหานี้ยังคงมีอยู่ ฉันมี setTimeOut สำหรับ div ที่มี a transitionดังนั้นจึงไม่ใช่การเปลี่ยน div ทั้งหมดในเวลาเดียวกัน แต่จริงๆแล้ว 15ms หลังจากแต่ละอันสร้างเอฟเฟกต์การหมุน เมื่อฉันไปที่แท็บอื่นและกลับมาหลังจากนั้นสักครู่การเปลี่ยน div ทั้งหมดในเวลาเดียวกันและsetTimeOutจะถูกละเว้นโดยสิ้นเชิง ไม่ใช่ปัญหาใหญ่สำหรับโครงการของฉัน แต่เป็นการเพิ่มที่แปลกและไม่ต้องการ
Rvervuurt

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

คำตอบ:


89

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

บางทีนี่อาจช่วยได้: ฉันจะทำให้ setInterval ทำงานได้อย่างไรเมื่อแท็บไม่ได้ใช้งานใน Chrome

TL; DR:ใช้แรงงานเว็บ


3
ขอบคุณฉันควรดูด้วย 'แท็บไม่ใช้งาน' การไม่พูดภาษาอังกฤษเป็นภาษาแม่ถือเป็นข้อบกพร่องในบางครั้ง
KooiInc

1
@Kooilnc: ไม่มีปัญหา :) ฉันไม่ใช่เจ้าของภาษาอังกฤษเหมือนกัน
pimvdb

22

มีวิธีแก้ปัญหาในการใช้ Web Workers เนื่องจากพวกเขาทำงานในกระบวนการแยกกันและไม่ช้าลง

ฉันได้เขียนสคริปต์เล็ก ๆ ที่สามารถใช้งานได้โดยไม่ต้องเปลี่ยนแปลงโค้ดของคุณ - เพียงแค่แทนที่ฟังก์ชัน setTimeout, clearTimeout, setInterval, clearInterval

เพียงใส่ไว้ก่อนรหัสทั้งหมดของคุณ

http://github.com/turuslan/HackTimer


7
นั่นเป็นสิ่งที่ดีและทั้งหมด แต่โปรดทราบว่า: 1. คนงานไม่สามารถเข้าถึง DOM ได้ 2. คนงานจะถูกดำเนินการก็ต่อเมื่อพวกเขาอยู่ในไฟล์ด้วยตัวเอง มันไม่ได้หล่นแทน setTimeout สำหรับหลายกรณี
Madara's Ghost

1
คุณพูดถูก แต่เบราว์เซอร์สมัยใหม่บางตัวอนุญาตให้ใช้คนงานโดยไม่มีไฟล์ของตัวเองโดยใช้ Blobs ( html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers )
Ruslan Tushov

1
แม้ว่าจะเป็นเช่นนั้น Web Workers ก็ยังขาดฟังก์ชันการทำงานจำนวนมาก (กล่าวคือ DOM) ที่ช่วยให้สามารถทดแทน setTimeout และ co ได้อย่างปลอดภัย
Madara's Ghost

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

คุณสามารถสร้างคนงานพนักงานบริการและใช้ canvas API โดยใช้ data-url new Worker('data:text/javascript,(' + function myWorkerCode () { /*...*/ } + '()'). นอกจากนี้ยังเป็นวิธีที่ดีในการตรวจสอบว่าคุณมีการรองรับนิพจน์การนำเข้าหรือไม่:try { eval('import("data:text/javascript,void 0")') } catch (e) { /* no support! */ }
Fábio Santos

9

การเล่นเสียง ~ ว่างจะบังคับให้เบราว์เซอร์รักษาประสิทธิภาพไว้ - ฉันค้นพบมันหลังจากอ่านความคิดเห็นนี้: จะทำให้ JavaScript ทำงานด้วยความเร็วปกติใน Chrome ได้อย่างไรแม้ว่าแท็บจะไม่ทำงานก็ตาม

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

นี่คือ 2 ลูปเสียงว่างเปล่าที่ฉันสร้างขึ้นเพื่อจุดประสงค์นี้คุณสามารถใช้มันได้อย่างอิสระในเชิงพาณิชย์: http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

(รวมถึงเสียง -58db, -60db ไม่ทำงาน)

ฉันเล่นตามความต้องการของผู้ใช้ด้วย Howler.js: https://github.com/goldfire/howler.js

function performance_trick()
{
    if(sounds.empty) return sounds.empty.play();
    sounds.empty = new Howl({
        src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
        volume:0.5,
        autoplay: true, loop: true,
    });
}

เป็นเรื่องน่าเศร้าที่ไม่มีวิธีการในตัวในการเปิด / ปิดประสิทธิภาพจาวาสคริปต์เต็มรูปแบบตามค่าเริ่มต้น แต่นักขุดคริปโตสามารถจี้เธรดการประมวลผลทั้งหมดของคุณโดยใช้ Web Workers โดยไม่ต้องแจ้งให้ทราบ: |


ขอบคุณ 58db สามารถรับฟังได้ดีกับหูฟัง แต่การปิดเว็บไซต์ช่วยแก้ปัญหานั้นได้
Kaan Soral

1

ฉันได้ปล่อยช่วงเวลาของผู้ปฏิบัติงานแล้วแพ็คเกจ npmซึ่งใช้ setInterval และ clearInterval โดยใช้ Web-Workers เพื่อติดตามและทำงานบนแท็บที่ไม่ใช้งานสำหรับ Chrome, Firefox และ IE

เบราว์เซอร์สมัยใหม่ส่วนใหญ่ (Chrome, Firefox และ IE) ช่วงเวลา (ตัวจับเวลาหน้าต่าง) ถูก จำกัด ให้เริ่มทำงานไม่บ่อยเกินหนึ่งครั้งต่อวินาทีในแท็บที่ไม่ได้ใช้งาน

คุณสามารถค้นหาข้อมูลเพิ่มเติมได้ที่

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals


0

ฉันอัปเดตแกน jQuery เป็น 1.9.1 และแก้ไขความคลาดเคลื่อนของช่วงเวลาในแท็บที่ไม่ได้ใช้งาน ฉันจะลองก่อนจากนั้นดูตัวเลือกการแทนที่โค้ดอื่น ๆ


คุณอัปเกรดจากเวอร์ชันใด ฉันประสบปัญหาการหมดเวลา (แถบเลื่อนแกลเลอรี) กับเวอร์ชัน ~ 1.6
dmi3y

0

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

<script>

var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];

function getCurrentMillis(){
    var d = new Date();
    var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
    return now;
}

function setAccurateTimeout(callbackfunction, millis, id=0){
    nowMillisTimeout[id] = getCurrentMillis();
    timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}

function setAccurateInterval(callbackfunction, millis, id=0){
    nowMillisInterval[id] = getCurrentMillis();
    interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}

//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);

setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);

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