2010-12-04 4 views
10

Windows 시스템 가동 시간이 49.7에 가까워지면서 내부 Windows 밀리 초 틱 카운터는 2^32에 접근합니다. setInterval 또는 setTimeout 이벤트를 발생시킬시기를 계산할 때 Internet Explorer 8의 버그가 산술 오버플로가있는 것 같습니다. 예를 들어 가동 시간 49 일에가동 시간 49 일 후 IE8 setInterval 및 setTimeout 즉시 발생합니다.

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

으로 전화하면 func는 24 시간이 아니라 즉시 호출됩니다.

이 버그는 충분한 숫자가 setInterval 또는 setTimeout에 전달되면 25 일 가동 시간 (2^31 밀리 초) 후에 언제든지 발생합니다. (나는 49 일째에만 확인했습니다.)

명령 줄에 "net statistics server"를 입력하여 가동 시간을 확인할 수 있습니다.

해결 방법이 있습니까?

+0

질문이 있습니까 : 아래

이 문제를 해결하는 또 다른 버전인가? 해결 방법을 모색 중이거나 이것을 세계와 공유하고 있습니까? –

+0

Sooo ... 기본적으로 시스템 가동 시간이 25 일이 경과 한 후 24 시간 동안 시간 제한을 설정하면 버그가 발생한다고 말하는 것입니까? 시간 초과가 필요할 때가 궁금합니다. –

+0

IE8에서 버그를 더 많이 문서화하고 있습니다. 이것이 문제가 될 수있는 경우의 예를 들면, 1 시간 후에 타이머가 작동한다고하고, 사용자가 다른 페이지로 이동할 때이를 다른 페이지로 리디렉션한다고 가정 해보십시오. 작동 시간이 2 ~ 32 밀리 초의 1 시간 내에있게되면 타이머가 즉시 작동되고 사용자는 원래 페이지에 액세스 할 수 없게됩니다. 가동 시간이 2 ~ 32 밀리 초가되면 모든 것이 다시 작동하기 시작합니다. 하지만 한 시간 동안 페이지가 깨질 것입니다. – user281806

답변

5

당신은 여전히 ​​버그가 clearTimeout 여전히 사용할 수 있습니다 발생되지 않도록 경우 setTimeout에서 값을 반환이 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); 
} 

에 대한 래퍼를 사용하여 버그를 해결 할 수있다. clearTimeout에 방탄이 필요하거나 setInterval (그리고 아마도 clearInterval)이 필요하면 문제에 더 많은 코드를 추가해야하지만 func이 실행되기 전에 충분한 시간을 확인하는 교장이 필요합니다.

+0

감사합니다, 당신의 예가 나를 시작했습니다 – user281806

+0

그냥 브라우저 setTimeout을 대체 할 때 이것을 보았습니다. http://www.adequatelygood.com/2011/4/Replacing-setTimeout-Globally –

1

카메론 요르단의 대답에 변화 :

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); 
} 

도우미 기능의 목적은 IE8은 버그 상태에있는 경우 두 번째 한 번 자신을 호출하는 것입니다.

테스트를위한 유용한 유틸리티는 AdjustTickCount입니다 (Windows XP 만 해당). 예를 들어, 새 틱 수를 0xffff0000으로 설정하면 틱 카운터가 롤오버되기 전에 65 초의 버그가 발생합니다. 예를 들어 120 초로 설정된 타이머는 제대로 작동하지 않습니다.

또한 Windows XP에서는 버그가있는 setTimeout 동작이 this post에 따라 마우스 왼쪽 버튼에 연결되어있는 것으로 보입니다.

3

이 항목은 내가 작업 한 응용 프로그램의 주요 골칫거리를 해결하는 데 큰 도움이되었습니다. 은 게시 용으로에 감사합니다. AdjustTickCount 유틸리티는 솔루션을 증명할 수있는 환상적이고 필수적인 도구이므로 엄지 손가락으로 활용할 수도 있습니다.

이 문제는 IE 7에도 영향을 미치며 IE 6에도 영향을 미치는 것으로 나타 났지만 브라우저가 모두 응답을 멈추고 솔루션이 해당 버전에서도 작동하지 않는 것처럼 악화 될 수 있습니다. 특히 비즈니스/엔터프라이즈 분야에서이 오래된 버전의 사용자가 많이 있습니다.

Windows XP에서 왼쪽 마우스 단추가 문제 였음을 발견하지 못했지만 문제가 발생하지 않았습니다.

시간 초과 지연이 매우 많고 응용 프로그램에 설정된 시간 제한이 매우 적은 경우 처음 두 답변은 정상입니다. 시간 초과가 더 많이 요구되는 경우 웹 응용 프로그램을 사용할 수 없게되는 것을 방지하기 위해 더 많은 작업이 필요합니다. 웹 2.0 qooxdoo과 같은 프레임 워크를 사용하는 0 RIA는 며칠 동안 작동 상태를 유지할 수 있으므로 애니메이션 또는 기타 간단한 효과를 생성하려면 2/2 초 지연보다 더 긴 시간 제한이 더 필요할 수 있습니다.

첫 번째 해결 방법은 좋은 시작이지만 다음 시간 초과를 target-now으로 설정하면 가동 시간 + 지연 시간이 2^32 밀리 초를 초과하므로 JS 코드가 가동 시간까지 계속 회전하므로 함수가 즉시 호출됩니다. 0으로 감싼다 (또는 사용자가 브라우저를 죽인다). 지금 다른 코드를 살펴-에서 얻을 수있는 주위의 가동 시간 랩 1 초 내에 있지만, 실험 아직도 그 수 보여 까지 조기 제한 시간은 단 1 개 초 간격으로 발생하기 때문에

두 번째 솔루션은 개선 보류중인 타임 아웃이 충분한 경우 브라우저를 사용할 수 없도록 설정하십시오. 가동 시간이 끝날 때까지 계속 진행되므로 요청한 지연 시간이 길면 사용자가 여전히 브라우저를 죽이기로 결정할 수 있습니다.

CPU 사용량이 적은 솔루션은 지연 시간이 500ms 미만이 될 때까지 각 후속 시간 초과에 대한 지연을 이전 지연 시간의 절반으로 설정하는 것입니다. 가동 시간을위한 랩 어라운드 포인트가 임박한 시점입니다 (< 1 초 남았습니다) 다음 시간 초과를 target-now으로 설정하여 조기 시간 초과 검사가 더 적은 횟수의 추가주기 후에 중단되도록 할 수 있습니다. 이 작업을 수행하는 데 걸리는 시간은 원래 지연이 얼마나 오래되었는지, 가동 시간이 얼마나 가까워 졌는지에 따라 다릅니다. setSafeTimeout이 호출되었지만 결국에는 CPU로드가 최소화되어 사용자가 장기간의 속도 저하를 경험하지 않고 정상적인 작동으로 돌아갑니다. 이 같은

뭔가 :

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); 
}; 

또한 정제 :

내가 setTimeout() 때로는 몇 밀리 초 이전에 시스템 가동 시간 틱 경우에도 예상보다 콜백을 호출 할 수 있습니다 것으로 나타났습니다은 닫지 2입니다^32ms. 이 경우 위 함수에서 사용 된 다음 대기 간격은 원래 목표에 남아있는 시간보다 길어질 수 있으므로 원래 대기 시간보다 길어질 수 있습니다.

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

좋은 해결책입니다. – user281806

+0

감사합니다. 질문에 대한 표를 던지 겠지만 새 계정 보유자는 지금 당장이를 수행 할 수 없습니다. –