একটি সেটটাইমআউট () এ সময় বাকি আছে?


90

আমি এমন কিছু জাভাস্ক্রিপ্ট লিখছি যা লাইব্রেরি কোডের সাথে ইন্টারেক্ট করে যা আমার নিজের নয়, এবং (যুক্তিসঙ্গত) পরিবর্তন করতে পারে না। এটি জাভাস্ক্রিপ্ট সময়সীমা সীমাবদ্ধ প্রশ্নগুলির একটি সিরিজের পরবর্তী প্রশ্নটি দেখানোর জন্য ব্যবহৃত হয়। এটি আসল কোড নয় কারণ এটি সমস্ত আশা ছাড়িয়ে গেছে। পাঠাগারটি যা করছে তা এখানে:

....
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = setTimeout( showNextQuestion(questions[i+1]), t );

আমি এমন একটি অগ্রগতি বারটি অনস্ক্রিনে রাখতে চাই যা questionTime * 1000তৈরি টাইমারকে জিজ্ঞাসাবাদ করার মাধ্যমে পূর্ণ হয় setTimeout। একমাত্র সমস্যা হ'ল এটি করার কোনও উপায় নেই বলে মনে হয়। getTimeoutআমি অনুপস্থিত কোন ফাংশন আছে ? জাভাস্ক্রিপ্টের টাইমআউটগুলির একমাত্র তথ্য যা আমি পাই তা কেবলমাত্র তৈরির মাধ্যমে setTimeout( function, time)এবং মুছে ফেলার সাথে সম্পর্কিত clearTimeout( id )

আমি এমন একটি ফাংশন সন্ধান করছি যা হয় সময়সীমা অগ্নিকাণ্ডের আগে বাকি সময়টি ফেরত দেয়, বা সময়সীমা আহ্বানের পরে সময় কেটে যায়। আমার অগ্রগতি বার কোডটি দেখতে এমন দেখাচ্ছে:

var  timeleft = getTimeout( test.currentTimeout ); // I don't know how to do this
var  $bar = $('.control .bar');
while ( timeleft > 1 ) {
    $bar.width(timeleft / test.defaultQuestionTime * 1000);
}

tl; dr: জাভাস্ক্রিপ্ট সেটটাইমআউট () এর আগে কীভাবে বাকি সময়টি খুঁজে পাব?


সমাধান এখন আমি ব্যবহার করছি। আমি পরীক্ষাগারের দায়িত্বে থাকা লাইব্রেরি বিভাগটি দিয়ে গিয়েছিলাম এবং কোডটি বাতিল করেছিলাম (ভয়ানক এবং আমার অনুমতিগুলির বিপরীতে)।

// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = mySetTimeout( showNextQuestion(questions[i+1]), t );

এবং এখানে আমার কোড:

সেটটাইমআউটের জন্য // র‍্যাপার
ফাংশন মাইসেটটাইমআউট (ফানক, সময়সীমা) {
    সময়সীমা [এন = সেটটাইমআউট (ফানক, সময়সীমা)] = {
        শুরু: নতুন তারিখ ()। গেটটাইম (),
        শেষ: নতুন তারিখ ()। গেটটাইম () + টাইমআউট
        t: সময়সীমা
    }
    রিটার্ন এন;
}

এটি IE 6 নয় এমন কোনও ব্রাউজারে বেশ স্পট-অন কাজ করে Even এমনকি মূল আইফোনও, যেখানে আমি জিনিসগুলি অ্যাসিঙ্ক্রোনাস পাওয়ার আশা করছিলাম।

উত্তর:


31

আপনি যদি লাইব্রেরি কোডটি সংশোধন করতে না পারেন তবে আপনার উদ্দেশ্য অনুসারে আপনার সেটটাইমআউটটিকে পুনরায় সংজ্ঞা দিতে হবে। আপনি কী করতে পারেন তার একটি উদাহরণ এখানে:

(function () {
var nativeSetTimeout = window.setTimeout;

window.bindTimeout = function (listener, interval) {
    function setTimeout(code, delay) {
        var elapsed = 0,
            h;

        h = window.setInterval(function () {
                elapsed += interval;
                if (elapsed < delay) {
                    listener(delay - elapsed);
                } else {
                    window.clearInterval(h);
                }
            }, interval);
        return nativeSetTimeout(code, delay);
    }

    window.setTimeout = setTimeout;
    setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);

এটি প্রোডাকশন কোড নয়, তবে এটি আপনাকে সঠিক পথে রাখবে। মনে রাখবেন যে আপনি সময়সীমা অনুযায়ী কেবল একজন শ্রোতার সাথে বাঁধতে পারেন। আমি এটি দিয়ে বিস্তৃত পরীক্ষা করিনি, তবে এটি ফায়ারবগে কাজ করে।

আরও শক্তিশালী সমাধান সেটটাইমআউট মোড়ানোর একই কৌশলটি ব্যবহার করবে, তবে পরিবর্তিত প্রত্যাবর্তন সময়সীমার একটি মানচিত্র শ্রোতাদের কাছে টাইমআউট একাধিক শ্রোতাদের পরিচালনা করতে ব্যবহার করবে। আপনি ক্লিয়ারটাইমআউট মোড়ানোও বিবেচনা করতে পারেন তাই সময়সীমা সাফ হলে আপনি আপনার শ্রোতাকে আলাদা করতে পারেন।


ধন্যবাদ আপনি আমার দিন বাঁচিয়েছেন!
xecutioner

14
মৃত্যুদন্ড কার্যকর হওয়ার কারণে, এটি কিছুক্ষণের জন্য কয়েক মিলিসেকেন্ডে নেমে যেতে পারে। এটি করার আরও একটি নিরাপদ উপায় হল, আপনি যখন সময়সীমা (নতুন তারিখ ()) শুরু করেছিলেন তখন রেকর্ড করুন এবং তারপরে এটি কেবল বর্তমান সময় (অন্য নতুন তারিখ ()) থেকে বিয়োগ করুন
জোনাথন

61

কেবল রেকর্ডের জন্য, নোড.জেজে সময় বাকী রাখার উপায় রয়েছে:

var timeout = setTimeout(function() {}, 3600 * 1000);

setInterval(function() {
    console.log('Time left: '+getTimeLeft(timeout)+'s');
}, 2000);

function getTimeLeft(timeout) {
    return Math.ceil((timeout._idleStart + timeout._idleTimeout - Date.now()) / 1000);
}

মুদ্রণ:

$ node test.js 
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s

এটি ফায়ারফক্সে কাজ করছে বলে মনে হচ্ছে না, তবে যেহেতু নোড.জেএস জাভাস্ক্রিপ্ট, আমি ভেবেছিলাম এই মন্তব্যটি নোড সমাধানের সন্ধানের জন্য সহায়ক হতে পারে।


4
এটি নোডের নতুন সংস্করণ কিনা বা নিশ্চিত নয় তবে এটি কাজ করার জন্য আমাকে "গেটটাইম ()" অংশটি সরিয়ে ফেলতে হয়েছিল। দেখে মনে হচ্ছে _আইডল স্টার্ট ইতিমধ্যে এখন পূর্ণসংখ্যা
ক্যাস্টেলান

4
আমি এটি মাত্র 0.10 নোডে চেষ্টা getTime()করেছি, সরানো হয়েছে, _idleStartইতিমধ্যে সময় এসেছে
ট্যান

4
নোড .3.৩ এ কাজ করবেন না, কারণ সময়সীমা কাঠামো সেই তথ্য ফাঁস is
হুয়ান

53

সম্পাদনা: আমি আসলে আমার মনে হয় আমি আরও উন্নততর করেছি: https://stackoverflow.com/a/36389263/2378102

আমি এই ফাংশনটি লিখেছি এবং আমি এটি অনেক ব্যবহার করি:

function timer(callback, delay) {
    var id, started, remaining = delay, running

    this.start = function() {
        running = true
        started = new Date()
        id = setTimeout(callback, remaining)
    }

    this.pause = function() {
        running = false
        clearTimeout(id)
        remaining -= new Date() - started
    }

    this.getTimeLeft = function() {
        if (running) {
            this.pause()
            this.start()
        }

        return remaining
    }

    this.getStateRunning = function() {
        return running
    }

    this.start()
}

একটি টাইমার তৈরি করুন:

a = new timer(function() {
    // What ever
}, 3000)

সুতরাং আপনি যদি সময় চান তবে শুধু করুন:

a.getTimeLeft()

তার জন্য ধন্যবাদ. ঠিক আমি যা খুঁজছিলাম তা নয়, তবে সময় বাকী গণনা করা ফাংশন খুব দরকারী
পরিবর্তে

4

জাভাস্ক্রিপ্টের ইভেন্ট স্ট্যাকগুলি আপনাকে কীভাবে ভাববে তা পরিচালনা করে না।

একটি সময়সীমা ইভেন্ট তৈরি করা হলে এটি ইভেন্টের কাতারে যুক্ত করা হয়, তবে ইভেন্টটি চালিত হওয়ার সময় অন্যান্য ইভেন্টগুলি অগ্রাধিকার নিতে পারে, মৃত্যুদন্ড কার্যকর করার সময় এবং দৌড়ের সময় স্থগিত করে।

উদাহরণ: আপনি স্ক্রিনে কিছু সতর্ক করতে 10 সেকেন্ড দেরি করে একটি টাইমআউট তৈরি করেন। এটি ইভেন্ট স্ট্যাকের সাথে যুক্ত হবে এবং সমস্ত বর্তমান ইভেন্টগুলি বরখাস্ত করার পরে কার্যকর করা হবে (কিছুটা বিলম্বের কারণ হবে)। তারপরে, সময়সীমাটি প্রক্রিয়া করার পরে, ব্রাউজারটি এখনও অন্যান্য ইভেন্টগুলি ক্যাপচার অব্যাহত রাখে এগুলি স্ট্যাকের সাথে যুক্ত করে, যার ফলে প্রক্রিয়াজাতকরণে আরও বিলম্ব হয়। যদি ব্যবহারকারী ক্লিক করেন বা প্রচুর সিআরটিএল + টাইপ করে থাকেন তবে তাদের ইভেন্টগুলি বর্তমান স্ট্যাকের চেয়ে বেশি অগ্রাধিকার গ্রহণ করবে। আপনার 10 সেকেন্ড 15 সেকেন্ড বা তার চেয়েও বেশি সময় হতে পারে।


বলা হচ্ছে, কত সময় কেটে গেছে তা জাল করার অনেকগুলি উপায় রয়েছে। একটি উপায় হ'ল আপনি স্ট্যাকের মধ্যে সেটটাইমআউট যুক্ত করার পরে ঠিক একটি সেটইন্টারওয়াল কার্যকর করা।

উদাহরণ: 10 সেকেন্ড বিলম্বের সাথে একটি সেটটাইমআউট করুন (বিশ্বব্যাপী যে বিলম্বটি সঞ্চয় করুন)। তারপরে একটি সেটইন্টারভাল করুন যা প্রতি সেকেন্ডে দেরি করে 1 টি বিয়োগ করতে এবং দেরিটি বাকি রেখে আউটপুট করে। ইভেন্ট স্ট্যাক কীভাবে প্রকৃত সময়কে প্রভাবিত করতে পারে (উপরে বর্ণিত) এর কারণে, এটি এখনও সঠিক হবে না, তবে একটি গণনা দেয়।


সংক্ষেপে, বাকি সময় পাওয়ার কোনও আসল উপায় নেই। ব্যবহারকারীর কাছে অনুমান করার চেষ্টা করার উপায় রয়েছে।


4

সার্ভার পার্শ্ব নোড.জেএস নির্দিষ্ট

উপরের কোনওটিই সত্যই আমার পক্ষে কাজ করেনি এবং সময়সীমা অবলম্বন করার পরে দেখে মনে হয়েছিল যে প্রক্রিয়াটি কখন শুরু হয়েছিল তার সাথে সবকিছুই আপেক্ষিক ছিল। নিম্নলিখিত আমার জন্য কাজ করেছে:

myTimer = setTimeout(function a(){console.log('Timer executed')},15000);

function getTimeLeft(timeout){
  console.log(Math.ceil((timeout._idleStart + timeout._idleTimeout)/1000 - process.uptime()));
}

setInterval(getTimeLeft,1000,myTimer);

আউটপুট:

14
...
3
2
1
Timer executed
-0
-1
...

node -v
v9.11.1

সংক্ষিপ্ততার জন্য সম্পাদিত আউটপুট, তবে এই মৌলিক ফাংশনটি কার্যকর হওয়া বা মৃত্যুদন্ড কার্যকর হওয়ার সময় পর্যন্ত আনুমানিক সময় দেয়। অন্যরা যেমন উল্লেখ করেছেন, নোড প্রক্রিয়াগুলির উপায়গুলির কারণে এর কোনওটিই সঠিক হবে না, তবে আমি যদি 1 মিনিটেরও কম সময় আগে চালানো একটি অনুরোধটি দমন করতে চাই এবং টাইমারটি সঞ্চয় করি তবে কেন এটি হবে না তা আমি দেখতে পাচ্ছি না দ্রুত চেক হিসাবে কাজ। রিফ্রেশটাইমার দিয়ে 10.2+ এ অবজেক্টগুলিকে জগল করা আকর্ষণীয় হতে পারে।


1

আপনি করতে পারেন সংশোধন setTimeout একটি মানচিত্র প্রতিটি সময়সীমার শেষ সময় সংরক্ষণ এবং একটি ফাংশন বলা তৈরি করতে getTimeoutসময় একটি নির্দিষ্ট আইডি সহ একটি টাইমআউটের জন্য বাকি জন্য।

এই ছিল সুপার এর সমাধান , কিন্তু আমি এটা পরিবর্তিত সামান্য কম মেমরি ব্যবহার

let getTimeout = (() => { // IIFE
    let _setTimeout = setTimeout, // Reference to the original setTimeout
        map = {}; // Map of all timeouts with their end times

    setTimeout = (callback, delay) => { // Modify setTimeout
        let id = _setTimeout(callback, delay); // Run the original, and store the id
        map[id] = Date.now() + delay; // Store the end time
        return id; // Return the id
    };

    return (id) => { // The actual getTimeout function
        // If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0
        return map[id] ? Math.max(map[id] - Date.now(), 0) : NaN;
    }
})();

ব্যবহার:

// go home in 4 seconds
let redirectTimeout = setTimeout(() => {
    window.location.href = "/index.html";
}, 4000);

// display the time left until the redirect
setInterval(() => {
    document.querySelector("#countdown").innerHTML = `Time left until redirect ${getTimeout(redirectTimeout)}`;
},1);

এই getTimeout IIFE এর একটি সংক্ষিপ্ত সংস্করণ এখানে :

let getTimeout=(()=>{let t=setTimeout,e={};return setTimeout=((a,o)=>{let u=t(a,o);return e[u]=Date.now()+o,u}),t=>e[t]?Math.max(e[t]-Date.now(),0):NaN})();

আমি আশা করি এটি আপনার পক্ষে যেমন দরকারী তেমনি এটি আমার পক্ষেও ছিল! :)


0

না, তবে আপনার কার্যক্রমে অ্যানিমেশনের জন্য আপনার নিজস্ব সেটটাইমআউট / সেটইন্টারভাল থাকতে পারে।

আপনার প্রশ্নটি দেখতে এমনটি বলে:

function myQuestion() {
  // animate the progress bar for 1 sec
  animate( "progressbar", 1000 );

  // do the question stuff
  // ...
}

এবং আপনার অ্যানিমেশন এই 2 টি কার্য দ্বারা পরিচালিত হবে:

function interpolate( start, end, pos ) {
  return start + ( pos * (end - start) );
}

function animate( dom, interval, delay ) {

      interval = interval || 1000;
      delay    = delay    || 10;

  var start    = Number(new Date());

  if ( typeof dom === "string" ) {
    dom = document.getElementById( dom );
  }

  function step() {

    var now     = Number(new Date()),
        elapsed = now - start,
        pos     = elapsed / interval,
        value   = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar)

    dom.style.width = value + "px";

    if ( elapsed < interval )
      setTimeout( step, delay );
  }

  setTimeout( step, delay );
}

পার্থক্যটি কেবলমাত্র এমএসে পরিমাপ করা যায়, কারণ আপনার ফাংশনের শীর্ষে অ্যানিমেশনটি শুরু হয়। আমি দেখেছি আপনি jQuery ব্যবহার করেন। আপনি jquery.animate ব্যবহার করতে পারেন।
gblazex

সবচেয়ে ভাল উপায় হ'ল এটি নিজের জন্য চেষ্টা করে দেখার। :)
gblazex

0

কেউ যদি এই দিকে ফিরে তাকান। আমি একটি টাইমআউট এবং অন্তর ব্যবস্থাপক নিয়ে এসেছি যা আপনাকে সময়সামগ্রী বা বিরতিতে রেখে যাওয়ার পাশাপাশি কিছু অন্যান্য জিনিসপত্র পেতে পারে। আমি এটিকে আরও নিবিড় এবং আরও নির্ভুল করে তুলতে যুক্ত করব, তবে এটি মোটামুটিভাবে কাজ করবে বলে মনে হচ্ছে (যদিও এটিকে আরও নির্ভুল করার জন্য আমার আরও কিছু ধারণা রয়েছে):

https://github.com/vhmth/Tock


আপনার লিঙ্কগুলি ভাঙা হয়েছে
কিক বাট্টোস্কি

0

প্রশ্নের ইতিমধ্যে উত্তর দেওয়া হয়েছে তবে আমি আমার বিট যোগ করব। এটি আমার কাছে ঘটেছিল।

ব্যবহার করুন setTimeoutমধ্যে recursionনিম্নরূপ:

var count = -1;

function beginTimer()
{
    console.log("Counting 20 seconds");
    count++;

    if(count <20)
    {
        console.log(20-count+"seconds left");
        setTimeout(beginTimer,2000);
    }
    else
    {
        endTimer();
    }
}

function endTimer()
{
    console.log("Time is finished");
}

আমার ধারণা কোডটি স্ব-বর্ণনামূলক


0

এটি পরীক্ষা করুন:

class Timer {
  constructor(fun,delay) {
    this.timer=setTimeout(fun, delay)
    this.stamp=new Date()
  }
  get(){return ((this.timer._idleTimeout - (new Date-this.stamp))/1000) }
  clear(){return (this.stamp=null, clearTimeout(this.timer))}
}

একটি টাইমার তৈরি করুন:

let smtg = new Timer(()=>{do()}, 3000})

থাকুন:

smth.get()

সময়সীমা সাফ করুন

smth.clear()

0
    (function(){
        window.activeCountdowns = [];
        window.setCountdown = function (code, delay, callback, interval) {
            var timeout = delay;
            var timeoutId = setTimeout(function(){
                clearCountdown(timeoutId);
                return code();
            }, delay);
            window.activeCountdowns.push(timeoutId);
            setTimeout(function countdown(){
                var key = window.activeCountdowns.indexOf(timeoutId);
                if (key < 0) return;
                timeout -= interval;
                setTimeout(countdown, interval);
                return callback(timeout);
            }, interval);
            return timeoutId;
        };
        window.clearCountdown = function (timeoutId) {
            clearTimeout(timeoutId);
            var key = window.activeCountdowns.indexOf(timeoutId);
            if (key < 0) return;
            window.activeCountdowns.splice(key, 1);
        };
    })();

    //example
    var t = setCountdown(function () {
        console.log('done');
    }, 15000, function (i) {
        console.log(i / 1000);
    }, 1000);

0

আমি এই উত্তরটি খুঁজতে এখানেই থামলাম, তবে আমার সমস্যাটিকে ওভারটিনিং করছিলাম। আপনি যদি এখানে থাকেন কারণ আপনার সেটটাইমআউট চলছে যখন আপনার কেবল সময়ের ট্র্যাক রাখা দরকার, এটি করার আরও একটি উপায় এখানে রয়েছে:

    var focusTime = parseInt(msg.time) * 1000

    setTimeout(function() {
        alert('Nice Job Heres 5 Schrute bucks')
        clearInterval(timerInterval)
    }, focusTime)

    var timerInterval = setInterval(function(){
        focusTime -= 1000
        initTimer(focusTime / 1000)
    }, 1000);

0

একটি দ্রুত এবং সহজ উপায়:

tmo = 1000;
start = performance.now();
setTimeout(function(){
    foo();
},tmo);

আপনি এর সাথে বাকি সময়টি পেতে পারেন:

 timeLeft = tmo - (performance.now() - start);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.