Jaka jest wersja JavaScript funkcji sleep ()?


2335

Czy jest lepszy sposób na inżynierię sleepw JavaScript niż następująca pausecompfunkcja ( wzięta stąd )?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

To nie jest kopia Sleep w JavaScript - opóźnienie między czynnościami ; Chcę prawdziwego snu w środku funkcji, a nie opóźnienia przed wykonaniem fragmentu kodu.


4
Należy go ustawić w połowie chwili, jeśli użyję setTimeout, czas ten będzie kontynuował przetwarzanie i ustawianie w kolejce więcej setTimeouts, które ostatecznie będą działały w tym samym czasie i
zapewnią

159
To okropne rozwiązanie - będziesz żuć cykle przetwarzania, nie robiąc nic.
17 z 26

12
Jedynym celem snu jest odpytywanie lub oczekiwanie na oddzwonienie - zarówno setInterval, jak i setTimeout działają lepiej niż to.
annakata

1
Prawdopodobnie możesz robić, co chcesz, z kontynuacją przekazywania stylu w JavaScript. Spójrz na ten artykuł.
Ognyan Dimitrov

Odpowiedzi:


2559

Aktualizacja 2017-2019

Od 2009 roku, kiedy zadano to pytanie, JavaScript ewoluował znacznie. Wszystkie pozostałe odpowiedzi są teraz przestarzałe lub nadmiernie skomplikowane. Oto obecna najlepsza praktyka:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later, showing sleep in a loop...');

  // Sleep in loop
  for (let i = 0; i < 5; i++) {
    if (i === 3)
      await sleep(2000);
    console.log(i);
  }
}

demo();

To jest to. await sleep(<duration>).

Lub jako jedna linijka:

await new Promise(r => setTimeout(r, 2000));

Zauważ, że

  1. awaitmoże być wykonywany tylko w funkcjach poprzedzonych asyncsłowem kluczowym lub na najwyższym poziomie skryptu w niektórych środowiskach (np. konsola Chrome DevTools lub Runkit).
  2. awaitwstrzymuje tylko bieżącą asyncfunkcję

Dwie nowe funkcje JavaScript pomogły napisać tę funkcję „uśpienia”:

Zgodność

Jeśli z jakiegoś dziwnego powodu używasz Węzła starszego niż 7 (który osiągnął koniec życia ) lub celujesz w stare przeglądarki, async/ awaitnadal możesz go używać za pośrednictwem Babel (narzędzie, które przetłumaczy JavaScript + nowe funkcje na zwykły stary JavaScript) , z transform-async-to-generatorwtyczką.


5
Świetne rzeczy tutaj. Zastanawiam się, w jaki sposób wpływa to lub odnosi się do współczesnych stanów „aktywnych” / „nieaktywnych” przeglądarek po wywołaniu przez JS trybu „uśpienia”? Czy przeglądarka może zablokować tryb uśpienia zgodnie z oczekiwaniami dla ogólnego JS, aby przypomnieć sobie później, kiedy stanie się „aktywny”, czy też ma inne zachowanie?
Andre Canilho,

18
Jaka jest obecna obsługa tego przeglądarki? Nie uważałbym poprzednich rozwiązań za „przestarzałe”, dopóki to rozwiązanie nie będzie obsługiwane przez zdecydowaną większość przeglądarek, a przynajmniej wszystkie popularne. Przeciwnie, uważałbym to rozwiązanie za interesujące, ale nieużyteczne / niepraktyczne, dopóki nie uzyska szerokiego poparcia.
Alvin Thompson,

74
To nie jest „prawdziwy sen” i nie odpowiada na pytanie. Osoba, która zadała pytanie, wyraźnie odróżniła stackoverflow.com/questions/758688/sleep-in-javascript od swojego pytania. Podczas rzeczywistego snu nie można wykonać żadnego innego kodu (chyba że w innym wątku). Ta odpowiedź jest dobra na inne pytanie.
9

4
@ jacroe - transpiler obsługuje funkcje strzałek, a także async / await (co i tak spowodowałoby wymiotowanie krwi przez IE)
Jaromanda X

11
@niry JavaScript, jako język jednowątkowy, nie nadaje się do „prawdziwego” snu, ponieważ działa w tym samym wątku co interfejs użytkownika i powodowałby brak reakcji na strony internetowe.
Patrick Roberts,

849

(Zobacz zaktualizowaną odpowiedź na 2016 r. )

Myślę, że jest całkowicie rozsądne chcieć wykonać akcję, poczekać, a następnie wykonać inną akcję. Jeśli jesteś przyzwyczajony do pisania w językach wielowątkowych, prawdopodobnie masz pomysł na wykonanie przez określony czas, dopóki wątek się nie obudzi.

Problem polega na tym, że JavaScript jest modelem jednowątkowym opartym na zdarzeniach. Podczas gdy w konkretnym przypadku fajnie byłoby poczekać cały silnik na kilka sekund, ogólnie jest to zła praktyka. Załóżmy, że chciałem skorzystać z twoich funkcji podczas pisania własnych? Gdy wywołałem twoją metodę, wszystkie moje metody się zawiesiły. Jeśli JavaScript mógłby w jakiś sposób zachować kontekst wykonania twojej funkcji, zapisz ją gdzieś, a następnie przywróć i kontynuuj później, wtedy sen może się zdarzyć, ale to w zasadzie wątek.

Więc utknąłeś z tym, co sugerowali inni - musisz podzielić kod na wiele funkcji.

Twoje pytanie jest więc trochę fałszywym wyborem. Nie ma sposobu na spanie tak, jak chcesz, ani nie powinieneś szukać proponowanego rozwiązania.


45
To wcale nie jest poprawna odpowiedź. Jeśli JavaScript nie ma funkcji uśpienia, dzieje się tak tylko dlatego, że ECMAScript jej nie wymaga. Jest to wybór projektowy organu odpowiedzialnego za projektowanie Javascript. Mogło być tak, że czas wykonywania Javascript czeka określony czas przed uruchomieniem następnego wiersza kodu, ale nie wybrano go.
Didier A.

5
Sen może być doskonale zaimplementowany w JavaScript, choć nie z precyzją w czasie rzeczywistym. W końcu jest to system oparty na zdarzeniach. Po zakończeniu wywołań asynchronicznych następuje zdarzenie. Nie widzę powodu, dla którego to samo nie może być możliwe po wydaniu polecenia sleep (), po którym kontrola jest zwracana do przeglądarki, aż do zakończenia snu, zwracając kontrolę do funkcji wywołującej. I tak, zgadzam się również, że czasami sen jest przydatny, zwłaszcza gdy programiści PRZED spieprzyliście projekt tak bardzo, że NIE macie innego wyjścia poza całkowicie refaktoryzacją, na którą nie macie czasu
Lawrence

Wypróbuj Hypnotic, który jest zgodny z tym pomysłem: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat

4
Nazywanie javascript jednowątkowym jest mitem. Choć może to być technicznie poprawne, funkcjonalnie działa jak wielowątkowy język. Symulacja fork () jest banalnie łatwa i chociaż wydajność () nie jest tak naprawdę możliwa do wdrożenia, możesz zbliżyć się do niej, używając pamięci współdzielonej do blokowania / semaforów. Dla przeciętnego programisty sensowne jest traktowanie go jako wielowątkowego; nazwa techniczna ma znaczenie tylko dla twórców języka.
Benubird

8
Zgadzam się, dlaczego sleep()nie jest to możliwe w JS i że w większości przypadków są lepsze sposoby na robienie rzeczy. Ale nadal uważam sposób, w jaki silnik łączy wszystkie rzeczy, jako wadę projektową; nie ma powodu, dla którego język nie mógłby mieć sleep()funkcji ograniczonej do określonego skryptu, strony lub funkcji bez silnika blokującego procesor i zamrażającego aplikację jak maniak. Jest rok 2015 i nie powinieneś mieć możliwości awarii całej przeglądarki internetowej while(1). Mamy Flash do takich rzeczy.
Beejor

660

W JavaScript, przepisuję każdą funkcję, aby mogła zakończyć się jak najszybciej. Chcesz przywrócić kontrolę nad przeglądarką, aby mogła wprowadzać zmiany w DOM.

Za każdym razem, gdy chciałem spać w środku mojej funkcji, refaktoryzowałem użycie setTimeout().

Edytować

Niesławna funkcja snu lub opóźnienia w dowolnym języku jest przedmiotem wielu dyskusji. Niektórzy powiedzą, że zawsze powinien być sygnał lub oddzwonienie, aby uruchomić daną funkcjonalność, inni twierdzą, że czasami przydatny jest dowolny moment opóźnienia. Mówię, że każdemu ich własna i jedna zasada nigdy nie może dyktować niczego w tej branży.

Pisanie funkcji uśpienia jest proste i jeszcze bardziej użyteczne dzięki skryptom JavaScript:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});

190
W drodze zamknięcia. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
chaos

68
ok, a co jeśli kod nie jest przeznaczony do użycia na stronie internetowej?
Eugenio Miró

10
@ EugenioMiró, jeśli kod nie jest przeznaczony do użycia na stronie internetowej, poproś, aby model obiektowy hosta zaimplementował metodę uśpienia. - Myślę, że pytanie dotyczy DOM, który jest narażony na działanie javascript działającego na stronach internetowych.
BrainSlugs83

31
@Nosredna tak, rozumiemy, jak wykonywać połączenia asynchroniczne, to nie pomaga nam spać (). Chcę, aby moje połączenia były wykonywane w określonej kolejności i aby dane były przywracane w określonej kolejności. Mam 5 poziomów w pętli for. Chcę ZABLOKOWAĆ wykonanie. Prawdziwa metoda uśpienia nie „spowolniłaby przeglądarki”, przespała ręce z powrotem do przeglądarki i innych wątków, które oczekują czasu procesora, gdy jest on nadal blokowany.
BrainSlugs83

382
to nie jest odpowiedź na pytanie.
TMS

302

Tylko dla debugowania / tworzenia , publikuję to, jeśli jest to przydatne dla kogoś

Ciekawe rzeczy, we Firebug (i prawdopodobnie innych konsolach js) nic się nie dzieje po wciśnięciu Enter, tylko po określonym czasie snu (...)

function sleepFor( sleepDuration ){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
}

Przykład zastosowania:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }

36
To nie jest odpowiedź. Jest dokładnie taki sam jak kod w pytaniu, z wyjątkiem nieco krótszego.
jab

16
Zajęty, naprawdę? W JS? Na sekundę? Jeśli złapię robiąc to stronę internetową, zostanie ona zablokowana.
mafu

34
@mafu Dlatego mówi only for debug/dev... rolleyes
xDaizu

11
NIGDY NIE Rób tego. Spowoduje to, że procesor uderzy w 100% w wykonywany rdzeń i zablokuje go.
noego

3
Jest to przydatne i być może JEDYNY sposób na spanie w aplikacji javascript z wiersza poleceń, ponieważ asynchronizacja / oczekiwanie nie jest pomocne.
Wheezil

177

Zgadzam się z innymi plakatami, zajęty sen to po prostu zły pomysł.

Jednak setTimeout nie wstrzymuje wykonania, wykonuje następny wiersz funkcji natychmiast po ustawieniu limitu czasu, a nie po upływie limitu czasu, aby nie wykonać tego samego zadania, które wykonałby sen.

Sposobem na to jest podzielenie funkcji na części przed i po części.

function doStuff()
{
  //do some things
  setTimeout(continueExecution, 10000) //wait ten seconds before continuing
}

function continueExecution()
{
   //finish doing things after the pause
}

Upewnij się, że nazwy funkcji nadal dokładnie opisują, co robi każdy element (IE GatherInputThenWait i CheckInput, a nie funcPart1 i funcPart2)

Edytować

Ta metoda osiąga cel polegający na tym, że nie wykonuje wierszy kodu, które zdecydujesz do momentu PO przekroczeniu limitu czasu, jednocześnie zwracając kontrolę z powrotem do komputera klienckiego, aby wykonać wszystko, co ustawiło w kolejce.

Dalsza edycja

Jak wskazano w komentarzach, absolutnie NIE zadziała to w pętli. Możesz zrobić fantazyjne (brzydkie) hakowanie, aby działało w pętli, ale ogólnie rzecz biorąc, spowoduje to katastrofalny kod spaghetti.


12
Tak. To staje się trudne, gdy masz pętlę lub nawet pętlę zagnieżdżoną. Musisz zrezygnować z pętli i zamiast tego mieć liczniki.
Nosredna

Touché. To znaczy, nadal byłoby to możliwe, ale w tym przypadku brzydkie i hackerskie. Możesz również użyć niektórych statycznych zmiennych stanu logicznego, ale jest to również dość hackerskie.
DevinB

2
-1 za to. Ponownie, to nie odpowiada na pytanie. Jest to raczej odpowiedź na pytanie takie jak „Jak wykonać funkcję asynchronicznie”, co znacznie różni się od „Jak zablokować wykonanie kodu”.
Deepak GM

6
@Nosredna Nie, użyłbyś zamknięcia. Na przykład: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }i for(var X = 0; X < 3;X++) { foo(X); }- przekazywana jest wartość X foo, która następnie zostaje ponownie użyta pod nazwą, indexgdy foo_continuezostanie ostatecznie wywołana.
Izkata

2
@Alexander Oczywiście, że tak, ponieważ celem setTimeout () jest zapobieganie blokowaniu się przeglądarki przez asychroniczne uruchamianie kodu. Umieść console.log()wnętrze foo_continue()w wersji setTimeout, a otrzymasz ten sam wynik.
Izkata

132

Z miłości do $ DEITY proszę nie robić funkcji spania z czekaniem. setTimeouti setIntervalrób wszystko, czego potrzebujesz.

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

Co dwie sekundy interwał ukrywa tekst na jedną sekundę. To pokazuje, jak używać setInterval i setTimeout do pokazywania i ukrywania tekstu co sekundę.


3
Cóż, nie do końca wszystko: setInterval robi znacznie lepsze wrażenie odpytywania.
annakata

3
Czego ten fragment kodu nie powstrzyma w silniku JavaScript?
Deniz Dogan

10
O ile nie potrzebujesz synchronizacji snu, w takim przypadku jest to całkowicie uzasadnione pytanie.
Aaron Dufour,

36
Myślę, że wielu z nas zapomina, że ​​JavaScript nie jest językiem tylko przeglądarki. Ten gość może tworzyć narzędzie wiersza poleceń Node, które wymaga krótkiej pauzy bez konieczności radzenia sobie ze wszystkimi problemami zakresu zmiennych, które występują w setTimeout.
Phil LaNasa

3
@PhilLaNasa: Jeśli zamknięcie składniowe wciąż jest przerażające, trzeba poważnie zapiąć pasy i przejść przez Węzeł 101.
chaos

113

Wiem, że to trochę stare pytanie, ale jeśli (podobnie jak ja) używasz Javascript z Rhino, możesz użyć ...

try
{
  java.lang.Thread.sleep(timeInMilliseconds);
}
catch (e)
{
  /*
   * This will happen if the sleep is woken up - you might want to check
   * if enough time has passed and sleep again if not - depending on how
   * important the sleep time is to you.
   */
}

4
Czy to połączenie z Javą?
Ken Sharp

14
To jest Java, a nie Javascript
RousseauAlexandre

18
@RousseauAlexandre Incorrect. Jest to JavaScript korzystający z Rhino (w tym czasie mógłby to być Nashorn)
mjaggard

71

Jeśli używasz jQuery, ktoś faktycznie stworzył wtyczkę „opóźniającą”, która jest niczym więcej niż opakowaniem dla setTimeout:

// Delay Plugin for jQuery
// - http://www.evanbot.com
// - © 2008 Evan Byrne

jQuery.fn.delay = function(time,func){
    this.each(function(){
        setTimeout(func,time);
    });

    return this;
};

Następnie możesz po prostu użyć go w szeregu wywołań funkcji zgodnie z oczekiwaniami:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');

4
To nie jest złe rozwiązanie. Zachowuje kontekst i łańcuchowość.
Nosredna

39
Począwszy od jQuery 1.4, .delay()jest częścią jQuery (choć z semantyką inną niż powyższa implementacja). api.jquery.com/delay
Matt Ball

7
Na to pytanie zdecydowanie brakowało odpowiedzi jQuery . Tak się cieszę, że to mamy!
xDaizu

1
Jeśli potrzebujesz opóźnienia między dwoma niezależnymi połączeniami, tak. Jeśli potrzebujesz opóźnień, aby zwolnić pętlę, nie.
WGroleau

46

Ja też szukałem rozwiązania uśpienia (nie kodu produkcyjnego, tylko Dev / Testy) i znalazłem ten artykuł:

http://narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html

... a oto kolejny link do rozwiązań po stronie klienta: http://www.devcheater.com/

Ponadto, gdy dzwonisz alert(), Twój kod również zostanie wstrzymany, gdy wyświetlany jest alert - musisz znaleźć sposób, aby nie wyświetlać alertu, ale uzyskać ten sam efekt. :)


35
Zgadzam się, wiele osób mówi: „Nie, nie rób tego w kodzie produkcyjnym!” Tak, um, nie chcę. Chcę to zrobić w wyrzuconym kodzie testowym, w wyniku czego nie chcę spędzać dużo czasu na tworzeniu eleganckiego rozwiązania.
user435779,

31

Oto proste rozwiązanie wykorzystujące synchroniczny XMLHttpRequest:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

zawartość sleep.php:

<?php sleep($_GET['n']);

Teraz nazwij to: sleep (5);


5
@lukad, użyj, setTimeout()jeśli to działa, ale jeśli to oznacza rozwikłanie 1000 linii zwrotnych, może to nie wyglądać jak żart.
pguardiario

11
Unikalne podejście, choć niestety niesynchroniczne żądania XMLHttp są przestarzałe i zostaną usunięte w przyszłości. Co jest zabawne, ponieważ właśnie ten fakt doprowadził mnie do tego pytania.
Beejor

To naprawdę dobry pomysł IMO. Chociaż nie uważam, że uśpiony interfejs API (Request URL) powinien być publiczny, ponieważ można go nadużywać.
Vahid Amiri

@Beejor myślenie zawsze tylko o przyszłości oznacza życie na futurystycznej
nierzeczywistości

Fajnie, ale czy wiesz, że czasami internet jest wolny lub czas pingowania witryny jest długi, to skrypt będzie spał dłużej niż czas na argumenty. Na przykład, jeśli używasz sleep(300)i witryna potrzebuje 150 ms na odpowiedź, to kod javascript będzie spał przez 450ms. a jeśli połączenie internetowe zostanie utracone przez przeglądarkę, będzie działać tylko przez 0 ms. Więc to nie jest lepsze rozwiązanie
H Chauhan

30

Proszę bardzo. Jak mówi kod, nie bądź złym deweloperem i używaj tego na stronach internetowych. Jest to funkcja narzędzia programistycznego.

// Basic sleep function based on ms.
// DO NOT USE ON PUBLIC FACING WEBSITES.
function sleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}

17
To w zasadzie to samo, co PO.
Andrew Barber

5
Mówiąc ściślej, OP poprosił o ALTERNATYWĘ.
WGroleau,

Rozwiązanie nie jest dobre, ale w niektórych miejscach async/awaitniestety nie reaguje i musimy go obowiązkowo stosować.
Nabi KAZ

21

Osobiście podoba mi się prosty:

function sleep(seconds){
    var waitUntil = new Date().getTime() + seconds*1000;
    while(new Date().getTime() < waitUntil) true;
}

następnie:

sleep(2); // Sleeps for 2 seconds

Cały czas używam go do tworzenia fałszywego czasu ładowania podczas tworzenia skryptów w P5js


3
Widzę to jako najbardziej zoptymalizowaną wersję głównego pytania: nie wykonuje żadnej matematyki wewnątrz pętli, a jedynie zwykłe porównanie. Jest to trochę trudne do odczytania.
hegez

4
NIGDY NIE Rób tego. Czy sprawdziłeś użycie procesora podczas działania tej funkcji? Powinno być blisko 100%, jeśli dasz na to wystarczająco dużo czasu.
noego

2
@hegez: Biorąc pod uwagę, że pętla będzie działać przez ustalony czas na zegarze ściennym bez względu na wszystko, wydaje się, że optymalizacja pętli jest trochę poza tym.
ShadowRanger

@noego Jak to? Właśnie przetestowałem w węźle 10, nie mam żadnej zmiany wykorzystania procesora
melMass

@melMass Ta funkcja po prostu blokuje wątek węzła na n sekund, utrzymując procesor w 100% zajęty. To „rozwiązanie” jest bardzo złym pomysłem z tych dwóch powodów (blokowanie + killer procesora). Oczekiwanie MUSI być nieblokujące, dlatego asynchroniczne.
Jeremy Thille

20

Pierwszy:

Zdefiniuj funkcję, którą chcesz wykonać w następujący sposób:

function alertWorld(){
  alert("Hello World");
}

Następnie zaplanuj jego wykonanie za pomocą metody setTimeout:

setTimeout(alertWorld,1000)

Zwróć uwagę na dwie rzeczy

  • drugim argumentem jest czas w milisekundach
  • jako pierwszy argument musisz podać tylko nazwę (odwołanie) funkcji, bez nawiasu

18

Lepszym rozwiązaniem, aby wyglądało tak, jak chce większość ludzi, jest skorzystanie z anonimowej funkcji:

alert('start');
var a = 'foo';
//lots of code
setTimeout(function(){  //Beginning of code that should run AFTER the timeout
    alert(a);
    //lots more code
},5000);  // put the timeout here

Jest to prawdopodobnie najbliższe osiągnięcie czegoś, co po prostu robi, co chcesz.

Uwaga: jeśli potrzebujesz wielu snu, może to być brzydkie w pośpiechu i może być konieczne ponowne przemyślenie projektu.


ten działał dla mnie w przeglądarkach komputerowych i starszym telefonie komórkowym. Inne, których próbowałem, nie działały na wszystkich.
Mike


10

W przypadku przeglądarek zgadzam się, że setTimeout i setInterval są właściwą drogą.

Ale w przypadku kodu po stronie serwera może to wymagać funkcji blokowania (na przykład w celu efektywnej synchronizacji wątków).

Jeśli używasz node.js i meteor, być może natrafiłeś na ograniczenia związane z używaniem setTimeout we włóknie. Oto kod uśpienia po stronie serwera.

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

Zobacz: https://github.com/laverdet/node-fibers#sleep


Server may require a blocking function... Nie wiem, jak mocno blokuje jedyny wątek Node i sprawia, że ​​cały serwer
przestaje

10

Chciałbym zawrzeć setTimeOut w obietnicy zgodności kodu z innymi zadaniami asynchronicznymi: Demo w skrzypcach

function sleep(ms)
{
    return(new Promise(function(resolve, reject) {        
        setTimeout(function() { resolve(); }, ms);        
    }));    
}

Używany w ten sposób:

sleep(2000).then(function() { 
   // Do something
});

Łatwo zapamiętać składnię, jeśli używałeś obietnic.


4
Dlaczego jest to lepsze niż używanie setTimeout (function () {/ * do coś * /}, 2000) ;?
JSideris,

10

Aktualizacja 2019 za pomocą Atomics.wait

Powinien działać w węźle 9.3 lub nowszym.

Potrzebowałem bardzo dokładnego timera w Node.js i działa świetnie do tego. Wydaje się jednak, że obsługa przeglądarek jest bardzo ograniczona.

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

Przebiegł kilka 10-sekundowych testów czasowych.

Dzięki setTimeout pojawia się błąd do 7000 mikrosekund. (7ms)

W przypadku Atomics mój błąd wydaje się utrzymywać poniżej 600 mikrosekund. (0,6 ms)

Aktualizacja 2020: Podsumowanie

function sleep(millis){ // need help of a server-side page
  let netMillis=Math.max(millis-5,0); //assuming 5ms overhead
  let xhr=new XMLHttpRequest();
  xhr.open('GET','/sleep.jsp?millis='+netMillis+'&rand='+Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}
function sleepAsync(millis){ // use only in async function
  let netMillis=Math.max(millis-1,0); // assuming 1ms overhead
  return new Promise((resolve)=>{
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}
async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}
function sleepSyncTest(){ 
  let source=`${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src='data:text/javascript,'+encodeURIComponent(source);
  console.log(src);
  var worker=new Worker(src);
}

z których np. sleep.jspwygląda strona po stronie serwera

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>

Moim zdaniem lepsze niż zaakceptowane rozwiązanie, które nie może być zaimplementowane jako prosta funkcja bez asynchronizacji / oczekiwania w dzwoniącym.
GroovyDotCom

tak, o ile masz świadomość, że to blokuje i że zwykle nie jest to dobre
Kapytanhook

Całkiem fajnie, ale fakt, że tak naprawdę jest obsługiwany tylko w Chrome i Firefox , nie sprawia, że ​​jest bardzo opłacalny do użytku w Internecie. (Lis 2019)
JGreatorex

9

Większość odpowiedzi tutaj jest błędnych lub przynajmniej nieaktualnych. Nie ma powodu, dla którego javascript musi być jednowątkowy, a tak nie jest. Obecnie wszystkie przeglądarki głównego nurtu obsługują pracowników, wcześniej inne środowiska wykonawcze javascript, takie jak Rhino i Node.js, obsługiwały wielowątkowość.

„Javascript jest jednowątkowy” nie jest prawidłową odpowiedzią. Na przykład uruchomienie funkcji uśpienia w ramach procesu roboczego nie zablokuje żadnego kodu działającego w wątku interfejsu użytkownika.

W nowszych środowiskach wykonawczych obsługujących generatory i wydajność można by wprowadzić podobną funkcjonalność do funkcji uśpienia w środowisku z jednym wątkiem:

// This is based on the latest ES6 drafts.
// js 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// run code you want to sleep here (ommit star if using js 1.7)
function* main(){
    for (var i = 0; i < 10; i++) {
        // to sleep for 10 milliseconds 10 times in a row
        yield 10;
    }

    yield 5;
    console.log('I just slept 5 milliseconds!');
}

// resume the given generator after ms milliseconds
function resume(ms, generator){
    setTimeout(function(){
        // ommit .value if using js 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// initialize generator and get first sleep for recursive function
var
    generator = main(),
    firstSleep = generator.next().value;

// initialize recursive resume function
resume(firstSleep, generator);

Ta imitacja snu różni się od prawdziwej funkcji snu, ponieważ nie blokuje wątku. Jest to po prostu cukier nad bieżącą funkcją setTimeout javascript. Ten typ funkcjonalności został zaimplementowany w Task.js i powinien działać dzisiaj w Firefox.


Pracownicy nie są implementowani w IE, przynajmniej w wersji 10. Która obecnie reprezentuje dużą liczbę użytkowników.
Beejor

To prawda, a nawet wtedy nie jest praktyczne wdrożenie sleepprzy użyciu wielu pracowników. Jeśli używasz Node.js, funkcje generatora są już zaimplementowane i mogą być używane zgodnie z opisem. Przeglądarki głównego nurtu nie mają na dzień dzisiejszy generatorów.
Gabriel Ratener

8

Przeszukałem / przeszukałem sporo stron internetowych na javascript sleep / wait ... i nie ma odpowiedzi, jeśli chcesz javascript do „URUCHAMIANIE, OPÓŹNIENIE, URUCHAMIANIE” ... to, co większość ludzi ma, to: „URUCHAMIANIE, URUCHAMIANIE (bezużyteczne) rzeczy), RUN ”lub„ RUN, RUN + opóźniony RUN ”....

Więc zjadłem kilka hamburgerów i pomyślałem ::: oto rozwiązanie, które działa ... ale musisz pokroić działające kody ... ::: tak, wiem, to jest po prostu łatwiejsze do odczytania refaktoryzacja .. . nadal...

//......................................... //Przykład 1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setInterval
var i = 0;

function run() {
    //pieces of codes to run
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } //end interval, stops run
    i++; //segment of code finished running, next...
}

run();
t=setInterval("run()",1000);

</script>
</body>
</html>

// .................................... // example2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function run() {
    //pieces of codes to run, can use switch statement
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(1000);}
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(2000);}
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(3000);}
    if (i==3){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()",dur);} //starts flow control again after dur

run(); //starts
</script>
</body>
</html>

// ................. przykład3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function flow() {
    run(i);
    i++; //code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i==5) {clearTimeout(t);} //stops flow, must be after sleep()
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow
</script>
</body>
</html>

// .............. przykład4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); //stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    i++; //current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow control for first time...
</script>
</body>
</html>

5
Ok, to działa z setTimeput, ale trudno jest zobaczyć, co się dzieje. Korzystanie z samego setTimeout jest łatwiejsze.
naugtur

7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

To to samo co prawdziwe pytanie. Nie ma sensu robić z tego prawdziwej odpowiedzi.
EML

2
Niezbyt dobre rozwiązanie - użycie tego w Selenium JavaScriptExecutor zawiesza moją przeglądarkę Chrome przez około 50% czasu na MacBooku Pro 2104.
szmergiel

7

Najkrótsze rozwiązanie bez żadnych zależności:

await new Promise(resolve => setTimeout(resolve, 5000));

Nie działa w IE11. Otrzymujemy błąd składniowy funkcji strzałki.
DDphp

@ Wykorzystanie Java-DKawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a

6

W JavaScript nie można tak spać, a raczej nie powinieneś. Uruchomienie pętli uśpienia lub chwili spowoduje zawieszenie przeglądarki użytkownika do momentu zakończenia pętli.

Użyj licznika czasu określonego w odnośniku, do którego się odwołujesz.


6

Jednym ze scenariuszy, w których możesz chcieć skorzystać z funkcji sleep () zamiast z setTimeout (), jest to, że masz funkcję odpowiadającą na kliknięcie użytkownika, która ostatecznie otworzy nowe, tj. Wyskakujące okno i zainicjujesz pewne przetwarzanie, które wymaga krótkiego okresu do wykonania przed wyświetleniem wyskakującego okienka. Przesunięcie otwartego okna do zamknięcia oznacza, że ​​przeglądarka zwykle blokuje je.


6

Rozumiem cel funkcji uśpienia, jeśli masz do czynienia z wykonywaniem synchronicznym. Funkcje setInterval i setTimeout tworzą równoległy wątek wykonania, który zwraca sekwencję wykonywania z powrotem do programu głównego, co jest nieskuteczne, jeśli trzeba czekać na dany wynik. Oczywiście można używać zdarzeń i procedur obsługi, ale w niektórych przypadkach nie jest to zamierzone.


6

Dodanie moich dwóch bitów. Potrzebowałem czasu oczekiwania na testy. Nie chciałem dzielić kodu, ponieważ byłoby to dużo pracy, więc dla mnie było to proste.

for (var i=0;i<1000000;i++){                    
     //waiting
  }

Nie widzę w tym żadnych wad i to załatwiło sprawę.


To może zostać skompilowane.
Viktor Sehr,

Proszę nie rób tego w ten sposób. Jest to blokujące wywołanie uśpienia, co oznacza, że ​​żaden inny skrypt javascript nie może zostać uruchomiony, gdy Twój kod blokuje wątek JS.
Steve Midgley

5
@SteveMidgley „żaden inny skrypt javascript [nie jest w stanie uruchomić], gdy twój kod blokuje wątek JS” wydaje mi się dokładnie tym, co OP chce robić ¯_ (ツ) _ / ¯
drigoangelo

1
Właśnie uruchomiłem kilka testów i wygląda na to, że nawet pusta pętla zablokuje przeglądarkę i procesor (nie tylko JavaScript). Korzystanie z forpętli prawie zawsze będzie wykonywane natychmiast, niezależnie od maksymalnej wartości i, a nawet ze złożonym kodem matematycznym umieszczonym w środku. Tak więc, chyba że czekasz tylko kilka milisekund, nadal nie ma sposobu na spanie z wdziękiem w JS.
Beejor

1 milion jest za duży. Dla mnie wystarczy 10k
Vlad

6

Można to zrobić przy użyciu metody uśpienia Java. Przetestowałem to w FF i IE i nie blokuje komputera, nie żuje zasobów ani nie powoduje niekończących się uderzeń serwera. Wydaje mi się to czystym rozwiązaniem.

Najpierw musisz załadować Javę na stronę i udostępnić jej metody. Aby to zrobić, zrobiłem to:

<html>
<head>

<script type="text/javascript">

  function load() {
    var appletRef = document.getElementById("app");
    window.java = appletRef.Packages.java;
  } // endfunction

</script>

<body onLoad="load()">

<embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />

Następnie wszystko, co musisz zrobić, aby uzyskać bezbolesną przerwę w JS, to:

java.lang.Thread.sleep(xxx)

Gdzie xxx to czas w milisekundach. W moim przypadku (dla uzasadnienia) była to część realizacji zamówienia zaplecza w bardzo małej firmie i musiałem wydrukować fakturę, którą trzeba było załadować z serwera. Zrobiłem to, ładując fakturę (jako stronę internetową) do ramki iFrame, a następnie drukując ramkę. Oczywiście musiałem poczekać, aż strona zostanie w pełni załadowana, zanim będę mógł wydrukować, więc JS musiał się zatrzymać. Osiągnąłem to, zmieniając ukryte pole formularza na stronie nadrzędnej za pomocą zdarzenia onLoad na stronie faktury (w ramce iFrame). A kod na stronie nadrzędnej do wydrukowania faktury wyglądał następująco (nieistotne części wycięte dla zachowania przejrzystości):

var isReady = eval('document.batchForm.ready');
isReady.value=0;

frames['rpc_frame'].location.href=url;

while (isReady.value==0) {
  java.lang.Thread.sleep(250);
} // endwhile

window.frames['rpc_frame'].focus();
window.frames['rpc_frame'].print();

Tak więc użytkownik naciska przycisk, skrypt ładuje stronę faktury, a następnie czeka, sprawdzając co kwadrans, czy strona faktury jest ładowana, a następnie wyświetla okno dialogowe drukowania, aby użytkownik mógł wysłać ją do drukarki. CO BYŁO DO OKAZANIA.


12
Wydaje się dość potworny soulution, biorąc pod uwagę prostą rzecz, którą autor chciał osiągnąć.
xaralis

2
Zależy to od przestarzałych apletów Java.
Vahid Amiri

6

Wiele odpowiedzi nie odpowiada (bezpośrednio) na pytanie, podobnie jak to ...

Oto moje dwa centy (lub funkcje):

Jeśli chcesz mniej nieporęcznych funkcji niż setTimeouti setInterval, możesz zawinąć je w funkcje, które po prostu odwracają kolejność argumentów i nadają im ładne nazwy:

function after(ms, fn){ setTimeout(fn, ms); }
function every(ms, fn){ setInterval(fn, ms); }

Wersje CoffeeScript:

after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms

Następnie możesz ich ładnie używać z anonimowymi funkcjami:

after(1000, function(){
    console.log("it's been a second");
    after(1000, function(){
        console.log("it's been another second");
    });
});

Teraz można go łatwo odczytać jako „po N milisekundach ...” (lub „co N milisekund ...”)


5

W konkretnym przypadku, gdy chcesz rozdzielić zestaw wywołań wykonywanych przez pętlę, możesz użyć czegoś takiego jak poniższy kod z prototypem. Bez prototypu można zastąpić funkcję opóźnienia setTimeout.

function itemHandler(item)
{
    alert(item);
}

var itemSet = ['a','b','c'];

// Each call to itemHandler will execute
// 1 second apart
for(var i=0; i<itemSet.length; i++)
{
    var secondsUntilExecution = i;
    itemHandler.delay(secondsUntilExecution, item)
}

5

Jeśli korzystasz z node.js, możesz rzucić okiem na włókna - natywne rozszerzenie C do węzła, rodzaj symulacji wielowątkowej.

Pozwala to robić prawdziwe sleepw sposób, który blokuje wykonanie we włóknie, ale nie blokuje w głównym wątku i innych włóknach.

Oto przykład z własnego pliku Readme:

// sleep.js

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

- a wyniki są:

$ node sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.