2010-12-04 11 views
10

Bir Windows sistemi, 49,7 günlük çalışma süresinin yakınındayken, dahili Windows milisaniği onay sayacı 2^32'ye yaklaşır. Internet Explorer 8'deki bir hata, bir setInterval veya setTimeout olayının ne zaman tetikleneceği hesaplanırken bir aritmetik taşma taşıyor gibi görünüyor. Örneğin, çalışma süresi gününde 49 üzerindedir ve fonk değil 24 saat içinde derhal adı verilecekIE8 setInterval ve setTimeout, çalışma süresinin 49 gününden hemen sonra tetiklenir

setInterval(func, 86400000); // fire event in 24 hours 

dersen.

Bu hata, büyük olasılıkla, setInterval veya setTimeout'a yeteri kadar büyük bir sayı iletildiyse, 25 günlük çalışma süresi (2^31 milisaniye) sonra herhangi bir zamanda meydana gelebilir. (Sadece 49. gün kontrol ettim.)

Komut satırında "net statistics server" yazarak çalışma gün sayısını kontrol edebilirsiniz.

Bir çözüm var mı?

+0

bir soru var mı: Aşağıda

bu sorunu gideren bir başka versiyonu nedir? Bir geçici çözüm arıyor veya bunu dünyayla mı paylaşıyorsunuz? –

+0

Sooo ... temelde, 24 saat boyunca sistem çalışma zamanının 24 saat sonra zaman aşımı yapılacağını mı söylüyorsun? Böyle bir zaman aşımına ne zaman ihtiyacım var acaba? –

+0

Bu, IE8'deki bir hatayı daha belgelemektedir. Bunun bir sorun olabileceği bir örnek için, bir saat sonra bir zamanlayıcı ateşinin olduğunu ve bir kullanıcıyı yangın olduğunda başka bir sayfaya yönlendirin. 2^32 milisaniyelik çalışma süresi bir saat içinde olduğunuzda, zamanlayıcı hemen tetiklenir ve kullanıcı orijinal sayfaya erişemez. Çalışma zamanı 2^32 milisaniye geçtiğinde, her şey tekrar çalışmaya başlayacaktır. Ama bu bir saat için sayfa kırılacak. – user281806

cevap

5

Hala hata clearTimeout hala kullanılabilir karşılaşılmaz eğer öyleyse setTimeout gelen değer döndüren bu setTimeout

function setSafeTimeout(func, delay){ 
    var target = +new Date + delay; 
    return setTimeout(function(){ 
     var now = +new Date; 
     if(now < target) { 
      setSafeTimeout(func, target - now); 
     } else { 
      func(); 
     } 
    }, delay); 
} 

için bir sarıcı kullanarak hata geçici olabilir. clearTimeout'un kurşun geçirmez olması gerekiyorsa veya setInterval (ve muhtemelen clearInterval) gerekiyorsa, daha fazla kod atmanız gerekir, ancak func bekletme işlemlerini gerçekleştirmeden önce yeterli zaman geçtiğini doğrulamanız gerekir.

+0

teşekkürler, örneğiniz beni başlattı – user281806

+0

Sadece bunu tarayıcı setTimeout değiştirerek gördüm: http://www.adequatelygood.com/2011/4/Replacing-setTimeout-Globally –

1

Cameron Jordan'ın cevabı bir varyasyonu:

function setSafeTimeout(func, delay) { 
    var target = +new Date + delay; 
    var helper = function() { 
     var now = +new Date; 
      if (now < target) { 
       setTimeout(arguments.callee, 1000); 
      } else { 
       func(); 
      } 
     } 
    return setTimeout(helper, delay); 
} 

yardımcı fonksiyonunun amacı IE8 hata durumunda ise ikinci bir kez kendisini çağırmaktır.

Test için yararlı bir yardımcı program AdjustTickCount'dur (yalnızca Windows XP olsa da). Örneğin, yeni kene sayımını 0xffff0000'e ayarlamak, kene sayacı devrilmeden önce 65 saniyelik buggy davranışını verecektir. Yani, 120 saniye olarak ayarlanmış herhangi bir zamanlayıcı düzgün bir şekilde ateş etmeyecektir.

Ayrıca, Windows XP'de, buggy setTimeout davranışı, this post'a göre tıklanan sol fare düğmesine bağlı görünüyordu.

3

Bu öğe, büyük bir üzerinde çalıştığım bir uygulamada büyük bir baş ağrısını çözmeye yardımcı oldu, gönderilmesi için. AdjustTickCount yardımcı programı, çözümleri kanıtlamak için fantastik ve önemli bir araçtır.

Sorun, IE 7'yi de etkiliyor ve ayrıca IE 6'yı etkiliyor gibi görünüyor, ancak tarayıcı hep birlikte yanıt vermeyi durdurduğu ve çözümlerin de bu sürümde işe yaramadığı için daha da kötü sonuçlarla karşılaşıyor. Bu eski sürümlerin çoğu, özellikle iş dünyasında/işletmelerde hala çok sayıda kullanıcı var.

Sol fare düğmesinin Windows XP'de bir faktör olduğunu bulamadım, sorun onsuz oluyor.

İlk iki cevap, zaman aşımı gecikmesi en çok saniyelerdeyse ve uygulamada ayarlanan çok az sayıda zaman aşımı sayısı varsa iyi olur. Daha fazla ve daha uzun zaman aşımı gerekiyorsa, web uygulamasının kullanılamaz hale gelmesini önlemek için daha fazla iş vardır. Bir Web'de 2.0 RIA, qooxdoo gibi bir çerçeve kullanarak günlerce çalışmayı bırakabilir, böylece animasyon veya başka kısa bir etki yaratmak için birkaç saniyelik gecikmeden daha fazla ve daha uzun zaman aşımına ihtiyaç duyulabilir.

İlk çözüm iyi bir başlangıçtır, ancak bir sonraki zaman aşımını target-now olarak ayarlamak, işlevinin derhal çağrılmasına neden olacaktır çünkü bu, çalışma zamanı + gecikme süresi 2^32 milisaniyeyi aşacaktır ve dolayısıyla JS kodu çalışma zamanına kadar dönecektir. 0'a kadar sarar (veya kullanıcı tarayıcıyı öldürür). Şimdi diğer kod bir göz-in ulaşmasını sağlar etrafında çalışma süresi sargı 1 saniye içinde ama deneyler hala can gösterdi kadar erken zaman aşımları sadece 1 saniye aralıklarla meydana gelecektir çünkü

ikinci çözüm bir gelişme Oyunda yeterince beklemede olan zaman aşımları varsa tarayıcıyı kullanılamaz hale getirmek için yeterli olun. Çalışma süresi düzelene kadar devam edecek ve istenen gecikme yeterince uzunsa kullanıcı yine de tarayıcıyı öldürmeye karar verebilir.

Daha az CPU'lu bir çözüm, her bir gecikme süresi için gecikmeyi, gecikme süresi 500ms'den az olana kadar önceki gecikme süresinin yarısına kadar ayarlamaktır. 1 saniye uzakta) ve bir sonraki zaman aşımını target-now'a ayarlayabiliriz, böylece erken zaman aşımı kontrolü sadece birkaç döngüden sonra durur. Buna ulaşmanın ne kadar sürmesi, orijinal gecikmenin ne kadar sürdüğüne ve setSafeTimeout numaralı telefonun ne zaman sona erdiğine ve sonunda en az CPU yüklemesi ile uygulamanın ne kadar uzun sürdüğüne bağlı olacak ve kullanıcı uzun süreli yavaşlama yaşamadan normal davranışa geri dönecektir. Böyle

şey:

function setSafeTimeout(func, delay) { 
    var target = +new Date + delay; 
    var newDelay = delay; 
    var helper = function() 
    { 
    var now = +new Date; 
    if (now < target) 
    { 
     newDelay /= 2; // halve the wait time and try again 
     if(newDelay < 500) // uptime wrap around is imminent 
     { 
     newDelay = target-now; // go back to using original target 
     } 
     var handle = setTimeout(helper, newDelay); 
     // if required record handle somewhere for clearTimeout 
    } 
    else 
    { 
     func(); 
    } 
    }; 
    return setTimeout(helper, delay); 
}; 

tekrar ince:

Ben setTimeout() bazen birkaç milisaniye daha erken sistem çalışma zamanı keneler bile beklenenden daha geri arama çağırabileceği bulduk değil yakın 2 etmektir^32ms. Bu durumda, yukarıdaki işlevde kullanılan bir sonraki bekleme aralığı, orijinal hedefe kalan süreden daha büyük olabilir; bu, başlangıçta istenenden daha uzun bir bekleme ile sonuçlanır.

function setSafeTimeout(func, delay) { 
    var target = +new Date + delay; 
    var newDelay = delay; 
    var helper = function() 
    { 
    var now = +new Date; 
    if (now < target) 
    { 
     var timeToTarget = target-now; 
     newDelay /= 2; // halve the wait time and try again 
     if(newDelay < 500 || newDelay > timeToTarget) // uptime wrap around is imminent 
     { 
     newDelay = timeToTarget; // go back to using original target 
     } 
     var handle = setTimeout(helper, newDelay); 
     // if required record handle somewhere for clearTimeout 
    } 
    else 
    { 
     func(); 
    } 
    }; 
    return setTimeout(helper, delay); 
}; 
+0

Güzel bir çözüm. – user281806

+0

Teşekkürler, soru için oy kullanacağım, ancak yeni hesap sahibi olarak şimdilik bunu yapmaktan sakınıyorum. –

İlgili konular