बड़े मिलीसेकंड देरी मूल्यों के लिए सेटटाइमआउट () "ब्रेक" क्यों होता है?


104

जब एक बड़ी मिलीसेकंड मान पास करने के दौरान मुझे कुछ अप्रत्याशित व्यवहार हुआ setTimeout()। उदाहरण के लिए,

setTimeout(some_callback, Number.MAX_VALUE);

तथा

setTimeout(some_callback, Infinity);

दोनों some_callbackको लगभग तुरंत चलाने का कारण है, जैसे कि मैं 0देरी के रूप में एक बड़ी संख्या के बजाय गुजर गया।

क्यों होता है ऐसा?

जवाबों:


143

यह सेटटाइमआउट के कारण 32 बिट इंट का उपयोग करके देरी को स्टोर करने के लिए होता है ताकि अधिकतम मूल्य की अनुमति हो

2147483647

अगर तुम कोशिश करो

2147483648

आप अपनी समस्या उत्पन्न कर रहे हैं।

मैं केवल यह मान सकता हूं कि यह जेएस इंजन में आंतरिक अपवाद के कुछ रूप को पैदा कर रहा है और समारोह को आग लगाने के बजाय बिल्कुल नहीं।


1
ठीक है, यह समझ में आता है। मुझे लगता है कि यह वास्तव में एक आंतरिक अपवाद नहीं बढ़ा रहा है। इसके बजाय, मैं इसे या तो (1) एक पूर्णांक अतिप्रवाह का कारण बनता हूं, या (2) आंतरिक रूप से एक अहस्ताक्षरित 32-बिट इंट वैल्यू के लिए देरी का कारण बनता हूं। यदि (1) मामला है, तो मैं वास्तव में देरी के लिए एक नकारात्मक मूल्य पारित कर रहा हूं। यदि यह (2) है, तो ऐसा कुछ delay >>> 0होता है, इसलिए पारित विलंब शून्य है। किसी भी तरह से, तथ्य यह है कि देरी को 32-बिट अहस्ताक्षरित इंट के रूप में संग्रहीत किया जाता है, इस व्यवहार की व्याख्या करता है। धन्यवाद!
मैट बॉल

पुराना अपडेट, लेकिन मैंने अभी अधिकतम सीमा पाई है 49999861776383( 49999861776384कॉलबैक के तुरंत आग लगने का कारण बनता है)
अधिकतम

7
@ मैक्सप इसलिए क्योंकि49999861776383 % 2147483648 === 2147483647
डेविड दा सिल्वा कंटिन

@ DavidDaSilvaContín को वास्तव में देर हो चुकी है, लेकिन क्या आप आगे बता सकते हैं? समझ में नहीं आता कि 2147483647 की सीमा क्यों नहीं है?
निक कोड

2
@ निक्कड़ दोनों संख्याओं में समान मात्रा में देरी होगी (अर्थात 49999861776383 हस्ताक्षरित 32 बिट बिंदु से 2147483647 के समान है)। उन्हें बाइनरी में लिखें, और अंतिम 31 बिट्स लें, वे सभी 1s होंगे।
मार्क फिशर

24

आप उपयोग कर सकते हैं:

function runAtDate(date, func) {
    var now = (new Date()).getTime();
    var then = date.getTime();
    var diff = Math.max((then - now), 0);
    if (diff > 0x7FFFFFFF) //setTimeout limit is MAX_INT32=(2^31-1)
        setTimeout(function() {runAtDate(date, func);}, 0x7FFFFFFF);
    else
        setTimeout(func, diff);
}

2
यह अच्छा है, लेकिन हम पुनरावृत्ति के कारणClearTimeout का उपयोग करने की क्षमता को ढीला कर देते हैं।
एलन निनहुई

2
आप वास्तव में इसे रद्द करने की क्षमता नहीं खोते हैं बशर्ते कि आप अपनी बहीखाता पद्धति को बदल दें और टाइमआउट को बदल दें जो आप इस फ़ंक्शन के अंदर रद्द करना चाहते हैं।
चार

23

कुछ स्पष्टीकरण यहाँ: http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html

टाइमआउट मान एक हस्ताक्षरित 32-बिट पूर्णांक में फिट होने के लिए बहुत बड़ा है, जिससे एफएफ, सफारी और क्रोम में अतिप्रवाह हो सकता है, जिसके परिणामस्वरूप टाइमआउट तुरंत निर्धारित किया जाता है। यह इन अर्थों को समयबद्ध नहीं करने के लिए अधिक समझ में आता है, क्योंकि 24.8 दिन ब्राउज़र के खुले रहने के लिए एक उचित अपेक्षा से परे है।


2
वॉरपेच का जवाब बहुत मायने रखता है - एक नोड की तरह लंबी चलने वाली प्रक्रिया। जेएस सर्वर एक अपवाद की तरह लग सकता है, लेकिन ईमानदार होने के लिए अगर आपको कुछ ऐसा मिला है जो आप सुनिश्चित करना चाहते हैं कि यह ठीक 24 और मिलिसेकंड सटीकता के साथ थोड़े दिनों में होता है। तो आप सर्वर और मशीन त्रुटियों के चेहरे पर setTimeout की तुलना में अधिक मजबूत कुछ का उपयोग करना चाहिए ...
cfogelberg

@cfogelberg, मैंने FF या किसी अन्य के कार्यान्वयन को नहीं देखा है setTimeout(), लेकिन मुझे उम्मीद है कि वे तारीख और समय की गणना करेंगे जब इसे जागना चाहिए और कुछ बेतरतीब ढंग से परिभाषित टिक पर एक काउंटर को कम नहीं करना चाहिए ... (एक उम्मीद कर सकते हैं) कम से कम)
एलेक्सिस विल्के

2
मैं एक सर्वर पर NodeJS में जावास्क्रिप्ट चला रहा हूं, 24.8 दिन अभी भी अच्छा है, लेकिन मैं 1 महीने (30 दिन) में होने वाले कॉलबैक को सेट करने के लिए अधिक तार्किक तरीके की तलाश कर रहा हूं। इसके लिए जाने का तरीका क्या होगा?
पॉल

1
मेरे पास निश्चित रूप से, ब्राउज़र विंडो 24.8 दिनों से अधिक खुली थी। यह मेरे लिए विचित्र है कि ब्राउज़र आंतरिक रूप से रोनेन के समाधान जैसा कुछ नहीं करते हैं, कम से कम MAX_SAFE_INTEGER तक
acjay

1
कौन कहता है? मैं अपने ब्राउज़र को 24 दिनों से अधिक समय तक खुला रखता हूं ...;)
पीट एल्विन

2

यहाँ टाइमर पर नोड डॉक देखें : https://nodejs.org/api/timers.html (संपूर्ण js के समान ही) क्योंकि यह एक ऐसा सर्वव्यापी शब्द है जो अब इवेंट लूप आधारित है

संक्षेप में:

जब विलंब 2147483647 से बड़ा या 1 से कम है, तो विलंब 1 पर सेट हो जाएगा।

और देरी है:

कॉलबैक से पहले प्रतीक्षा करने के लिए मिलीसेकंड की संख्या।

लगता है कि आपके टाइमआउट मान को इन नियमों के साथ अनपेक्षित मूल्य में डिफ़ॉल्ट रूप से लिया जा रहा है, संभवतः?


1

जब मैंने किसी उपयोगकर्ता को समाप्त सत्र के साथ स्वचालित रूप से लॉगआउट करने का प्रयास किया तो मैं इस पर अड़ गया। मेरा समाधान सिर्फ एक दिन के बाद टाइमआउट को रीसेट करना था, और स्पष्टता का उपयोग करने के लिए कार्यक्षमता रखना।

यहाँ थोड़ा प्रोटोटाइप उदाहरण है:

Timer = function(execTime, callback) {
    if(!(execTime instanceof Date)) {
        execTime = new Date(execTime);
    }

    this.execTime = execTime;
    this.callback = callback;

    this.init();
};

Timer.prototype = {

    callback: null,
    execTime: null,

    _timeout : null,

    /**
     * Initialize and start timer
     */
    init : function() {
        this.checkTimer();
    },

    /**
     * Get the time of the callback execution should happen
     */
    getExecTime : function() {
        return this.execTime;
    },

    /**
     * Checks the current time with the execute time and executes callback accordingly
     */
    checkTimer : function() {
        clearTimeout(this._timeout);

        var now = new Date();
        var ms = this.getExecTime().getTime() - now.getTime();

        /**
         * Check if timer has expired
         */
        if(ms <= 0) {
            this.callback(this);

            return false;
        }

        /**
         * Check if ms is more than one day, then revered to one day
         */
        var max = (86400 * 1000);
        if(ms > max) {
            ms = max;
        }

        /**
         * Otherwise set timeout
         */
        this._timeout = setTimeout(function(self) {
            self.checkTimer();
        }, ms, this);
    },

    /**
     * Stops the timeout
     */
    stopTimer : function() {
        clearTimeout(this._timeout);
    }
};

उपयोग:

var timer = new Timer('2018-08-17 14:05:00', function() {
    document.location.reload();
});

और आप इसे stopTimerविधि से साफ कर सकते हैं :

timer.stopTimer();

0

टिप्पणी नहीं कर सकते, लेकिन सभी लोगों को जवाब देने के लिए। यह अहस्ताक्षरित मूल्य लेता है (आप नकारात्मक मिलीसेकंड प्रतीक्षा नहीं कर सकते हैं) इसलिए चूंकि अधिकतम मूल्य "2147483647" है, जब आप उच्च मूल्य दर्ज करते हैं तो यह 0 से शुरू होता है।

मूल रूप से देरी = {VALUE}% 2147483647

तो 2147483648 की देरी का उपयोग करने से यह 1 मिलीसेकंड हो जाएगा, इसलिए, तत्काल खरीद।


-2
Number.MAX_VALUE

वास्तव में पूर्णांक नहीं है। सेटटाइमआउट के लिए अधिकतम स्वीकार्य मूल्य 2 ^ 31 या 2 ^ 32 है। प्रयत्न

parseInt(Number.MAX_VALUE) 

और आपको 1.7976931348623157e + 308 के बजाय 1 वापस मिलता है।


13
यह गलत है: Number.MAX_VALUEएक पूर्णांक है। 292 शून्य के बाद यह पूर्णांक 17976931348623157 है। कारण parseIntरिटर्न 1क्योंकि यह पहले एक स्ट्रिंग के लिए अपनी तर्क धर्मान्तरित और फिर स्ट्रिंग बाएं से दाएं खोज है। जैसे ही यह पता चलता है .(जो एक नंबर नहीं है), यह बंद हो जाता है।
पौआण

1
वैसे, यदि आप परीक्षण करना चाहते हैं कि क्या कोई पूर्णांक है, तो ES6 फ़ंक्शन का उपयोग करें Number.isInteger(foo)। लेकिन चूंकि यह अभी तक समर्थित नहीं है, आप Math.round(foo) === fooइसके बजाय उपयोग कर सकते हैं ।
पौआं

2
@Pauan, कार्यान्वयन के लिहाज से, Number.MAX_VALUEपूर्णांक नहीं बल्कि एक है double। तो वहाँ है कि ... एक डबल एक पूर्णांक का प्रतिनिधित्व कर सकता है, हालांकि, क्योंकि इसका उपयोग जावास्क्रिप्ट में 32 बिट्स के पूर्णांक को बचाने के लिए किया जाता है।
एलेक्सिस विलके

1
@AlexisWilke हाँ, बेशक जावास्क्रिप्ट 64-बिट फ्लोटिंग पॉइंट के रूप में सभी नंबरों को लागू करता है । यदि "पूर्णांक" से आपका मतलब है "32-बिट बाइनरी" तो Number.MAX_VALUEपूर्णांक नहीं है। लेकिन अगर "पूर्णांक" से आपका मतलब "पूर्णांक" की मानसिक अवधारणा से है, तो यह पूर्णांक है। जावास्क्रिप्ट में, क्योंकि सभी संख्याएं 64-बिट फ्लोटिंग पॉइंट हैं, इसलिए "पूर्णांक" की मानसिक अवधारणा परिभाषा का उपयोग करना आम है।
पौआन

वहाँ भी है Number.MAX_SAFE_INTEGERलेकिन यह वह संख्या नहीं है जिसकी हम यहाँ तलाश कर रहे हैं।
कांपना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.