thread loop ejemplo javascript sleep

loop - ¿Cuál es la versión de JavaScript de sleep()?



thread sleep javascript (30)

¿Hay una mejor manera de diseñar un sleep en JavaScript que la siguiente función pausecomp ( tomada de aquí )?

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

Esto no es un duplicado de Sleep en JavaScript - retraso entre acciones ; Quiero un sueño real en medio de una función, y no un retraso antes de que se ejecute un fragmento de código.


Actualización 2017

Desde 2009, cuando se hizo esta pregunta, JavaScript ha evolucionado significativamente. Todas las demás respuestas son ahora obsoletas o demasiado complicadas. Aquí está la mejor práctica actual:

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''); } demo();

Eso es todo. await sleep(<duration>) .

Puedes probar este código en vivo en Runkit . Tenga en cuenta que,

  1. await solo se puede ejecutar en funciones con el prefijo async . Runkit ajusta su código en una función asíncrona antes de ejecutarlo.
  2. await solo pausa la función async actual

Dos nuevas funciones de JavaScript ayudaron a escribir esta función real de "reposo":

Compatibilidad

Si, por alguna razón, está usando un nodo con más de 7 años o está apuntando a navegadores antiguos, async / await todavía se puede usar a través de Babel (una herramienta que transpile JavaScript + nuevas características al JavaScript antiguo), con transform-async-to-generator plugin transform-async-to-generator . correr

npm install babel-cli --save

Crea .babelrc con:

{ "plugins": [ "transform-async-to-generator", ] }

A continuación, ejecute su código con

node_modules/babel-cli/bin/babel-node.js sleep.js

Pero, de nuevo, no necesita esto si está usando el Nodo 7 o posterior, o si está apuntando a navegadores modernos.


(Ver la respuesta actualizada para 2016 )

Creo que es perfectamente razonable querer realizar una acción, esperar y luego realizar otra acción. Si está acostumbrado a escribir en lenguajes de múltiples subprocesos, probablemente tenga la idea de lograr la ejecución durante un tiempo determinado hasta que su hilo se despierte.

El problema aquí es que JavaScript es un modelo basado en eventos de un solo hilo. Mientras que en un caso específico, puede ser bueno que todo el motor espere unos segundos, en general es una mala práctica. Supongamos que quisiera usar tus funciones mientras escribo las mías. Cuando llamé a tu método, todos mis métodos se congelarían. Si JavaScript pudiera de alguna manera preservar el contexto de ejecución de su función, almacenarlo en algún lugar, luego recuperarlo y continuar más tarde, entonces podría producirse la suspensión, pero eso básicamente sería un subproceso.

Así que estás bastante atascado con lo que otros han sugerido, tendrás que dividir tu código en múltiples funciones.

Tu pregunta es un poco falsa, entonces. No hay forma de dormir de la manera que usted desea, ni debe buscar la solución que sugiere.


Añadiendo mis dos bits. Necesitaba una espera ocupada para propósitos de prueba. No quería dividir el código ya que eso sería mucho trabajo, así que un simple lo hizo por mí.

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

No veo ningún inconveniente en hacer esto y lo hizo el truco para mí.


Aquí hay una solución simple utilizando un XMLHttpRequest síncrono:

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

contenido de sleep.php:

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

Ahora llámalo con: sleep (5);


Aqui tienes. Como dice el código, no seas un mal desarrollador y usa esto en sitios web. Es una función de utilidad de desarrollo.

// 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) {} }


En JavaScript, reescribo cada función para que pueda terminar lo antes posible. Desea que el navegador vuelva a tener el control para que pueda realizar cambios en su DOM.

Cada vez que quería un sueño en medio de mi función, setTimeout() a utilizar un setTimeout() .

Voy a editar esta respuesta porque me pareció útil:

La función infame del sueño, o retraso, dentro de cualquier idioma es muy debatida. Algunos dirán que siempre debería haber una señal o devolución de llamada para activar una funcionalidad determinada, otros argumentarán que a veces es útil un momento arbitrario de demora. Digo que a cada uno lo suyo y una regla nunca puede dictar nada en esta industria.

Escribir una función de suspensión es simple y aún más utilizable con las promesas de JavaScript:

// sleep time expects milliseconds function sleep (time) { return new Promise((resolve) => setTimeout(resolve, time)); } // Usage! sleep(500).then(() => { // Do something after the sleep! });


Estoy de acuerdo con los otros carteles, un sueño ocupado es solo una mala idea.

Sin embargo, setTimeout no detiene la ejecución, ejecuta la siguiente línea de la función inmediatamente después de que se establece el tiempo de espera, no después de que expire el tiempo de espera, por lo que no cumple la misma tarea que una suspensión.

La forma de hacerlo es desglosar su función en antes y después de las piezas.

function doStuff() { //do some things setTimeout(continueExecution, 10000) //wait ten seconds before continuing } function continueExecution() { //finish doing things after the pause }

Asegúrese de que los nombres de sus funciones aún describan con precisión lo que está haciendo cada pieza (IE GatherInputThenWait y CheckInput, en lugar de funcPart1 y funcPart2)

Editar

Este método logra el propósito de no ejecutar las líneas de código que usted decide hasta DESPUÉS de su tiempo de espera, mientras sigue devolviendo el control al PC cliente para ejecutar cualquier otra cosa que haya puesto en cola.

Edición adicional

Como se señaló en los comentarios, esto absolutamente NO FUNCIONARÁ en un bucle. Podrías hacer un pirateo sofisticado (feo) para que funcione en un bucle, pero en general eso hará que el código de espagueti sea desastroso.


He buscado / buscado en varias páginas web en javascript sleep / wait ... y NO hay respuesta si quieres javascript para "RUN, DELAY, RUN" ... lo que la mayoría de la gente obtuvo fue "RUN, RUN (inútil cosas), RUN "o" RUN, RUN + RUN retrasado "....

Así que comí algunas hamburguesas y me puse a pensar ::: aquí hay una solución que funciona ... pero debes cortar los códigos de ejecución ... ::: sí, lo sé, esto es solo una refactorización más fácil de leer ... . todavía...

//......................................... //Ejemplo 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>

// ................. ejemplo3:

<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>

// .............. ejemplo 4:

<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>


La mayoría de las respuestas aquí son erróneas o, como mínimo, están desactualizadas. No hay razón para que javascript tenga un solo hilo, y de hecho no lo es. Hoy en día, todos los navegadores principales son compatibles con los trabajadores, antes de este caso, otros tiempos de ejecución de javascript como Rhino y Node.js admitían multithreading.

''Javascript es un solo hilo'' no es una respuesta válida. Por ejemplo, ejecutar una función de suspensión dentro de un trabajador no bloquearía ninguno de los códigos que se ejecutan en el subproceso de la interfaz de usuario.

En tiempos de ejecución más nuevos que admiten generadores y rendimiento, se podría brindar una funcionalidad similar a la función de suspensión en un entorno de un solo hilo:

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

Esta imitación del sueño es diferente de una función de sueño real, ya que no bloquea el hilo. Es simplemente el azúcar en la parte superior de la función setTimeout actual de javascript. Este tipo de funcionalidad se ha implementado en Task.js y debería funcionar hoy en Firefox.


Para los navegadores, estoy de acuerdo en que setTimeout y setInterval son el camino a seguir.

Pero para el código del lado del servidor, puede requerir una función de bloqueo (por ejemplo, para que pueda tener una sincronización de hilos efectiva).

Si está utilizando node.js y meteor, es posible que se haya topado con las limitaciones de usar setTimeout en una fibra. Aquí está el código para la suspensión del lado del servidor.

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

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


Personalmente me gusta el simple:

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

entonces:

sleep(2); // Sleeps for 2 seconds

Lo estoy usando todo el tiempo para crear tiempo de carga falso al crear scripts en P5js


Por amor a $ DEITY, por favor no haga una función de espera de espera ocupada. setTimeout y setInterval hacen todo lo que necesitas.


Primero:

Defina una función que quiera ejecutar así:

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

Luego programe su ejecución con el método setTimeout:

setTimeout(alertWorld,1000)

Nota dos cosas

  • El segundo argumento es el tiempo en milisegundos.
  • como primer argumento tiene que pasar solo el nombre (referencia) de la función, sin el paréntesis

Puedo entender el propósito de una función de suspensión si tiene que lidiar con la ejecución síncrona. Las funciones setInterval y setTimeout crean un hilo de ejecución paralelo que devuelve la secuencia de ejecución al programa principal, que es ineficaz si tiene que esperar un resultado dado. Por supuesto, uno puede usar eventos y manejadores, pero en algunos casos no es lo que se pretende.


Sé que esta es una pregunta antigua, pero si (como yo) estás usando Javascript con Rhino, puedes usar ...

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. */ }


Si está utilizando jQuery, alguien creó un complemento de "retraso" que no es más que un contenedor para 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; };

Luego puede usarlo en una fila de llamadas de función como se espera:

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



Un escenario en el que es posible que desee una función sleep () en lugar de usar setTimeout () es si tiene una función que responde a un clic del usuario que finalmente abrirá una nueva ventana emergente, es decir, si ha iniciado algún proceso que requiere un breve período para completar antes de que se muestre la ventana emergente. Mover la ventana abierta hacia un cierre significa que normalmente el navegador la bloquea.


Una mejor solución para hacer que las cosas parezcan lo que la mayoría de la gente quiere es usar una función anónima:

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

Probablemente esto sea lo más cercano a algo que simplemente hace lo que quieres.

Tenga en cuenta que si necesita dormir varias veces, esto puede ponerse feo rápidamente y es posible que deba replantearse su diseño.


Yo encapsularía setTimeOut en una Promesa para la consistencia del código con otras tareas asíncronas: Demo en Fiddle

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

Utilizado de esa manera:

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

Es fácil recordar la sintaxis si solías usar Promesas.


Solo para debug / dev , publico esto si es útil para alguien

Cosas interesantes, en Firebug (y probablemente en otras consolas js), no pasa nada después de pulsar enter, solo después de la duración del sueño especificada (...)

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

Ejemplo de uso:

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


Muchas de las respuestas no responden (directamente) a la pregunta, y esta tampoco ...

Aquí están mis dos centavos (o funciones):

Si desea funciones menos torpes que setTimeouty setInterval, puede envolverlas en funciones que solo inviertan el orden de los argumentos y les den buenos nombres:

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

Versiones de CoffeeScript:

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

Luego puedes usarlos bien con funciones anónimas:

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

Ahora se lee fácilmente como "después de N milisegundos, ..." (o "cada N milisegundos, ...")


Si tienes una función de sueño como esta

var sleep = function(period, decision, callback){ var interval = setInterval(function(){ if (decision()) { interval = clearInterval(interval); callback(); } }, period); }

y tienes una función asíncrona para llamar varias veces

var xhr = function(url, callback){ // make ajax request // call callback when request fulfills }

Y configuras tu proyecto así:

var ready = false; function xhr1(){ xhr(url1, function(){ ready = true;}); } function xhr2(){ xhr(url2, function(){ ready = true; }); } function xhr3(){ xhr(url3, function(){ ready = true; }); }

Entonces puedes hacer esto:

xhr1(); sleep(100, function(){ return done; }, xhr2); sleep(100, function(){ return done; }, xhr3); sleep(100, function(){ return done; }, function(){ // do more });

En lugar de interminable sangría de devolución de llamada como esta:

xhr(url1, function(){ xhr2(url2, function(){ xhr3(url3, function(){ // do more }); }); });


En primer lugar, setTimeout y setInterval es lo que se debe usar, debido a la naturaleza de devolución de llamada de javascript. Si desea utilizar sleep()es el flujo de control o la arquitectura de su código que es incorrecta.

Habiendo dicho eso, supongo que todavía puedo ayudar con dos implementaciones de un sueño.

  1. fingiendo correr sincrónico de la parte superior de mi cabeza:

    //a module to do taht //dual-license: MIT or WTF [you can use it anyhow and leave my nickname in a comment if you want to] var _=(function(){ var queue=[]; var play=function(){ var go=queue.shift(); if(go){if(go.a){go.f();play();}else{setTimeout(play,go.t);}} } return { go:function(f){ queue.push({a:1,f:f}); }, sleep:function(t){ queue.push({a:0,t:t}); }, playback:play } })();

    [Hacer la reproducción automática también debería ser posible]

    //usage _.go(function(){ //your code console.log(''first''); }); _.sleep(5000); _.go(function(){ //your code console.log(''next''); }); //this triggers the simulation _.playback();

  2. ejecución sincrónica real

Un día lo pensé mucho y la única idea que tuve para un verdadero sueño en JavaScript es técnica.

una función de suspensión tendría que ser una llamada AJAX síncrona con un tiempo de espera establecido en el valor de suspensión. Eso es todo y una única manera de tener un verdadero.sleep()


No puedes dormir así en JavaScript o, mejor dicho, no deberías. La ejecución de un ciclo de suspensión o de tiempo de espera hará que el navegador del usuario se bloquee hasta que se complete el ciclo.

Use un temporizador, como se especifica en el enlace al que hace referencia.


Para el caso específico de querer espaciar un conjunto de llamadas ejecutadas por un bucle, puede usar algo como el código a continuación con prototipo. Sin prototipo, puede sustituir la función de retardo con 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) }


Se puede hacer utilizando el método de suspensión de Java. Lo he probado en FF e IE y no bloquea la computadora, no mastica los recursos ni causa interminables visitas al servidor. Me parece una solución limpia.

Primero tienes que cargar Java en la página y hacer que sus métodos estén disponibles. Para hacer eso, hice esto:

<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" />

Entonces, todo lo que tienes que hacer cuando quieres una pausa indolora en tu JS es:

java.lang.Thread.sleep(xxx)

Donde xxx es el tiempo en milisegundos. En mi caso (a modo de justificación), esto fue parte del cumplimiento de pedidos de back-end en una empresa muy pequeña y tuve que imprimir una factura que tenía que cargarse desde el servidor. Lo hice cargando la factura (como una página web) en un iFrame y luego imprimiendo el iFrame. Por supuesto, tuve que esperar hasta que la página estuviera completamente cargada antes de poder imprimir, por lo que JS tuvo que pausar. Logré esto haciendo que la página de factura (en el iFrame) cambie un campo de formulario oculto en la página principal con el evento onLoad. Y el código en la página principal para imprimir la factura se veía así (partes irrelevantes cortadas para mayor claridad):

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

Así que el usuario presiona el botón, el script carga la página de la factura, luego espera, verifica cada cuarto de segundo para ver si la página de la factura ha terminado de cargarse, luego aparece el diálogo de impresión para que el usuario lo envíe a la impresora. QED.


Si estás en node.js, puedes echar un vistazo a las fibers : una extensión C nativa de node, una simulación de subprocesos de tipo un poco.

Le permite hacer un real sleepde una manera que está bloqueando la ejecución en una fibra, pero no es bloqueante en el hilo principal y otras fibras.

Aquí hay un ejemplo fresco de su propio léame:

// 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'');

- Y los resultados son:

$ 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)


Una pregunta antigua de 2009. Ahora en 2015 es posible una nueva solución con los generadores definidos en ECMAscript 2015, también conocido como ES6. Se aprobó en junio, pero antes se implementó en Firefox y Chrome. Ahora se puede hacer que una función de suspensión no esté ocupada, no bloquee y anidada dentro de bucles y subfunciones sin congelar el navegador. Solo se necesita JavaScript puro, no bibliotecas o marcos.

El siguiente programa muestra cómo sleep()y runSleepyTask()se puede hacer. La sleep()función es sólo una yielddeclaración. Es tan simple que en realidad es más fácil escribir la yielddeclaración directamente en lugar de llamar sleep(), pero entonces no habría ninguna palabra de reposo :-) El rendimiento devuelve un valor de tiempo al next()método interno wakeup()y espera. El verdadero "dormir" se hace en el wakeup()uso de la buena edad setTimeout(). En la devolución de llamada, el next()método activa la yieldinstrucción para continuar, y la "magia" del rendimiento es que todas las variables locales y toda la pila de llamadas a su alrededor aún están intactas.

Las funciones que usan sleep () o rendimiento deben definirse como generadores. Fácil de hacer agregando un asterisco a la palabra clave function*. Ejecutar un generador es un poco más complicado. Cuando se invoca con la palabra clave, newel generador devuelve un objeto que tiene el next()método, pero el cuerpo del generador no se ejecuta (la palabra clave newes opcional y no hace ninguna diferencia). El next()método activa la ejecución del cuerpo del generador hasta que encuentra a yield. La función de envoltorio runSleepyTask()inicia el ping-pong: next()espera a yield, y yieldespera a next().

Otra forma de invocar un generador es con palabras clave yield*, aquí funciona como una simple función de llamada, pero también incluye la capacidad de ceder next().

Todo esto se demuestra con el ejemplo drawTree(). Dibuja un árbol con hojas en una escena 3D giratoria. Un árbol se dibuja como un tronco con 3 partes en la parte superior en diferentes direcciones. Cada parte se dibuja como otro árbol más pequeño llamando de forma drawTree()recursiva después de un breve descanso. Un árbol muy pequeño se dibuja como sólo una hoja.

Cada hoja tiene su propia vida en una tarea separada comenzada con runSleepyTask(). Nace, crece, se sienta, se desvanece, cae y muere growLeaf(). La velocidad se controla con sleep(). Esto demuestra lo fácil que se puede hacer la multitarea.

function* sleep(milliseconds) {yield milliseconds}; function runSleepyTask(task) { (function wakeup() { var result = task.next(); if (!result.done) setTimeout(wakeup, result.value); })() } //////////////// written by Ole Middelboe ///////////////////////////// pen3D =setup3D(); var taskObject = new drawTree(pen3D.center, 5); runSleepyTask(taskObject); function* drawTree(root3D, size) { if (size < 2) runSleepyTask(new growLeaf(root3D)) else { pen3D.drawTrunk(root3D, size); for (var p of [1, 3, 5]) { var part3D = new pen3D.Thing; root3D.add(part3D); part3D.move(size).turn(p).tilt(1-p/20); yield* sleep(50); yield* drawTree(part3D, (0.7+p/40)*size); } } } function* growLeaf(stem3D) { var leaf3D = pen3D.drawLeaf(stem3D); for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)} yield* sleep( 1000 + 9000*Math.random() ); for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)} for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)} leaf3D.visible = false; } /////////////////////////////////////////////////////////////////////// function setup3D() { var scene, camera, renderer, diretionalLight, pen3D; scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 15, 20); renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7); directionalLight.position.set(-1, 2, 1); scene.add(directionalLight); scene.add(new THREE.AmbientLight(0x9999ff)); (function render() { requestAnimationFrame(render); // renderer.setSize( window.innerWidth, window.innerHeight ); scene.rotateY(10/60/60); renderer.render(scene, camera); })(); window.addEventListener( ''resize'', function(){ renderer.setSize( window.innerWidth, window.innerHeight ); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); }, false ); pen3D = { drawTrunk: function(root, size) { // root.skin = skin(0.5, 0.3, 0.2); root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16), root.skin).translateY(size/2)); root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16), root.skin).translateY(size)); return root; }, drawLeaf: function(stem) { stem.skin.color.setRGB(0, 1, 0); stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6), stem.skin) .rotateX(0.3).translateY(0.3)); stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2), stem.skin) .rotateX(0.3).translateY(0.4)); return stem; }, Thing: function() { THREE.Object3D.call(this); this.skin = new THREE.MeshLambertMaterial({ color: new THREE.Color(0.5, 0.3, 0.2), vertexColors: THREE.FaceColors, side: THREE.DoubleSide }) } }; pen3D.Thing.prototype = Object.create(THREE.Object3D.prototype); pen3D.Thing.prototype.tilt = pen3D.Thing.prototype.rotateX; pen3D.Thing.prototype.turn = pen3D.Thing.prototype.rotateY; pen3D.Thing.prototype.move = pen3D.Thing.prototype.translateY; pen3D.center = new pen3D.Thing; scene.add(pen3D.center); return pen3D; }

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

El material 3D está oculto dentro de setup3D () y solo se incluye para hacerlo menos aburrido que console.log (). Los ángeles se miden en radianes por cierto.

Probado para trabajar en Firefox y Chrome. No implementado en Internet Explore y iOS (iPads). Intenta ejecutarlo tú mismo.

Después de otro paso de las respuestas que encontré, Gabriel Ratener dio una respuesta similar hace un año: https://.com/a/24401317/5032384


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