El flujo de control es el orden en que se ejecuta el intérprete de JavaScript. declaraciones. Si una secuencia de comandos no incluye sentencias que alteren su flujo, ejecutarse de principio a fin, una línea a la vez. Las estructuras de control son que se usa para determinar si un conjunto de sentencias se ejecuta o no en función de un de criterios definidos, ejecutar un conjunto de sentencias de forma repetida o interrumpir una secuencia de declaraciones.
Instrucciones condicionales
Las instrucciones condicionales determinan si el código debe ejecutarse en función de uno o
más condiciones. Una sentencia condicional ejecuta el código que contiene si el
La condición asociada (o el conjunto de condiciones) se evalúa como true
. De lo contrario, el
el código fuente.
if
... else
else
Una sentencia if
evalúa una condición dentro de los paréntesis coincidentes que
en las conversaciones que sigues. Si la condición dentro de los paréntesis se evalúa como true
, la
o la declaración de bloqueo
que sigue los paréntesis coincidentes:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
Si la condición dentro de los paréntesis se evalúa como false
, la instrucción que
que sigue, se ignora:
if ( false ) console.log( "True." );
Una palabra clave else
que aparece inmediatamente después de una sentencia if
y su
ejecutada condicionalmente especifica la sentencia que se ejecutará si el
La condición if
se evalúa como false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
Para encadenar varias sentencias if
, puedes hacer lo siguiente:
declaración ejecutada condicionalmente después de else
otra declaración if
:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
Te recomendamos usar la sintaxis de la instrucción de bloqueo siguiendo los condicionales para
mejoran la legibilidad, pero las cláusulas else if
suelen ser una excepción a lo siguiente:
if ( myCondition === 5 ) {
console.log( "Five." );
} else if ( myCondition === 3 ) {
console.log( "Three" );
} else {
console.log( "Neither five nor three." );
}
> "Neither five nor three."
Operador ternario
if
ejecuta una sentencia de forma condicional. El operador ternario (con mayor precisión
pero con menos frecuencia se denomina operador condicional ternario) es la abreviatura.
para ejecutar una expresión de forma condicional. Como su nombre lo indica, la ternaria
es el único operador de JavaScript que usa tres operandos:
- Una condición que se evaluará, seguida de un signo de interrogación (
?
). - La expresión que se ejecutará si la condición se evalúa como
true
, seguida de un dos puntos (:
). - La expresión que se ejecutará si la condición se evalúa como
false
.
Con frecuencia, se usa para establecer o pasar un valor de forma condicional:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
... case
Usa la sentencia switch
para comparar el valor de una expresión con una lista de
valores potenciales definidos con una o más palabras clave case
. Esta sintaxis es
inusual, porque proviene de algunas de las primeras decisiones de diseño de JavaScript.
switch
... la sintaxis case
usa la palabra clave switch
, seguida de una expresión para
Se evaluará entre paréntesis, seguido de un par de llaves.
El cuerpo de switch
puede contener case
palabras clave, por lo general, una o más.
seguido de una expresión o valor, seguido de dos puntos (:
).
Cuando el intérprete alcanza un case
con un valor que coincide con la expresión que se muestra.
en el paréntesis después de la palabra clave switch
, ejecuta cualquier
sentencias que siguen a esa cláusula case
:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
Se ejecutan todas las sentencias posteriores a la case
coincidente, incluso si
encerrado en una declaración de bloqueo.
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
Un error de usar switch…case
es que, después de que se encuentra una coincidencia, el
El intérprete de JavaScript ejecuta cualquier sentencia que siga al case
coincidente.
incluso aquellos dentro de otras cláusulas case
. A esto se le llama "fallar" al
case
siguiente:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
Para evitar la duplicación, finaliza cada caso con la palabra clave break
, que
Detiene de inmediato la evaluación del cuerpo switch
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
Si no existe ningún elemento case
que coincida con el valor condicional, switch
selecciona default
.
si hay una:
switch ( 20 ) {
case 5:
console.log( "The value was five." );
break;
case 10:
console.log( "The value was ten." );
break;
default:
console.log( "The value was something unexpected." );
}
> "The value was something unexpected."
Sin embargo, la entrada también se aplica a default
, lo que podría generar
resultados inesperados. Para corregir esto, termina la sentencia default
con break
,
o colocarlo al final de la lista de casos.
switch ( 20 ) {
default:
console.log( "The value was something unexpected." );
case 10:
console.log( "The value was ten." );
break;
case 5:
console.log( "The value was five." );
break;
}
> The value was something unexpected.
> The value was ten.
Debido a que las cláusulas case
no requieren un
declaración de bloqueo para la agrupación
varias sentencias, las cláusulas case
y default
no crean
alcance léxico por sí mismos:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
Para administrar el alcance, usa sentencias de bloque:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
Iteraciones y bucles
Los bucles te permiten repetir un conjunto de sentencias mientras se cumple una condición. hasta que se cumpla una condición. Usar bucles para ejecutar un conjunto de instrucciones que de veces, hasta que se logre un resultado específico o hasta que Llega al final de una estructura de datos iterable (por ejemplo, el elemento final de un array, un mapa o un conjunto; la propiedad final de un objeto, o el último carácter de una cadena).
Los bucles interrumpen la parte superior a la inferior. de la ejecución de una secuencia de comandos mediante la iteración sobre un conjunto de sentencias hasta que se cumplan una o más condiciones, o ya no se según la sintaxis que se use para crear el bucle. Cuando termina el bucle, ejecución continúa con las instrucciones que le siguen. En el siguiente ejemplo, Las sentencias en el cuerpo del bucle se ejecutan tres veces antes de que Este intérprete sigue:
let iterationCount = 0;
console.log( "Pre-loop." );
while( iterationCount < 3 ) {
iterationCount++;
console.log( "Loop iteration." );
}
console.log( "Continuing on." );
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Continuing on."
Si no se pueden cumplir las condiciones durante la ejecución del bucle, este continúa indefinidamente. Estos bucles infinitos son un error de programación común que puede hace que el subproceso principal de ejecución se detengan de forma indefinida o bloqueen una pestaña del navegador.
El siguiente ejemplo se ejecutará mientras se mantenga el valor booleano true
.
true
Debido a que los valores booleanos son inmutables,
esto crea un bucle infinito.
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
Evita dejar bucles infinitos en tu código de producción. Si creas accidentalmente durante el desarrollo, puedes solucionarlo cerrando la pestaña del navegador en la que se ejecuta. actualizar tu código para que el bucle ya no sea infinito, y volver a abrir la .
while
Se crea un bucle while
con la palabra clave while
seguida de un par de
paréntesis coincidentes que contienen una condición que se evaluará. Si el estado especificado
condición se evalúa inicialmente como true
, la instrucción (o
instrucción de bloqueo) que le sigue
se ejecutan esos paréntesis. De lo contrario, el bucle nunca se ejecutará. Después de cada
iteración, se vuelve a evaluar la condición y, si sigue siendo true
, el bucle
se repita.
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
Si el intérprete encuentra una sentencia continue
en un bucle while
, la detiene.
e iteración, reevalúa la condición y continúa el bucle, si es posible:
let iterationCount = 0;
while( iterationCount <= 5 ) {
iterationCount++;
if( iterationCount === 3 ) {
continue;
}
console.log( `Loop ${ iterationCount }.` );
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Loop 4."
> "Loop 5."
> "Loop ended."
Si el intérprete encuentra una sentencia break
en un bucle while
, esa iteración
se detiene y la condición no se reevalúa, lo que permite que el intérprete continúe con lo siguiente:
let iterationCount = 1;
while( iterationCount <= 5 ) {
if( iterationCount === 3 ) {
console.log(`Iteration skipped.``);`
break;
}
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Iteration skipped.
> "Loop ended."
Puedes usar while
para iterar una cantidad específica de veces, como se ve en la
ejemplo anterior, pero el caso de uso más común para while
es un bucle de
longitud indeterminada:
let randomize = () => Math.floor( Math.random() * 10 );
let randomNum = randomize();
while( randomNum !== 3 ){
console.log( `The number is not ${ randomNum }.` );
randomNum = randomize();
}
console.log( `The correct number, ${ randomNum }, was found.` );
> "The number is not 0."
> "The number is not 6."
> "The number is not 1."
> "The number is not 8."
> "The correct number, 3, was found."
do
... while
do
... while
es una variante del bucle while
en la que la variable condicional
La evaluación ocurre al final de cada iteración del bucle. Esto significa que
del bucle se ejecuta siempre al menos una vez.
Para crear un bucle do
...while
, usa la palabra clave do
seguida de la sentencia.
(o instrucción de bloqueo)
que se ejecutará en cada iteración del bucle. Inmediatamente después de esa declaración, agrega
while
y paréntesis coincidentes que contienen la condición que se evaluará. Cuándo
esta condición ya no se evalúa como true
, el bucle finaliza.
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
Al igual que con un bucle while
, el caso de uso más común para do
...while
es un bucle de
longitud indeterminada:
let randomNum;
do {
randomNum = ( () => Math.floor( Math.random() * 10 ) )();
console.log( `Is the number ${ randomNum }?` );
} while ( randomNum !== 3 );
console.log( `Yes, ${ randomNum } was the correct number.` );
> "Is the number 9?"
> "Is the number 2?"
> "Is the number 8?"
> "Is the number 2?"
> "Is the number 3?"
> "Yes, 3 was the correct number."
for
Usa bucles for
para iterar en una cantidad conocida. En las bases de código heredadas, esta era
que suele usarse para iterar sobre los elementos de un array.
Para crear un bucle for
, usa la palabra clave for
seguida de un conjunto de paréntesis.
que acepte las siguientes tres expresiones en orden y separadas por
punto y coma:
- Una expresión que se evaluará cuando comience el bucle
- Una condición que determina si el bucle debe continuar
- Una expresión que se ejecutará al final de cada bucle
Después de estos paréntesis, agrega la instrucción (por lo general, un instrucción de bloqueo) que se ejecute durante el bucle.
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
La primera expresión inicializa una variable que actúa como un contador. Esta
se evalúa una vez, antes de la primera iteración del bucle. Puedes
inicializa esta variable usando let
(o var
, históricamente) como cualquier otro
variable y su alcance es el cuerpo del bucle. Estas variables pueden tener cualquier
identificador válido, pero con frecuencia se los llama i
para “iteración”. o "índice".
Esto parece contradecir lo establecido
prácticas recomendadas para nombres de identificadores predecibles,
pero la convención está lo suficientemente bien establecida como para ser clara para otros desarrolladores en
de un vistazo. Debido a que las colecciones indexadas no están indexadas,
estas variables casi siempre tienen un valor inicial de 0
.
Al igual que ocurre con otras formas de bucle, la condición es una expresión que determina
si el bucle debe ejecutarse. Se usa con mayor frecuencia para establecer
limitado para el contador de iteraciones. El intérprete evalúa la condición antes
ejecutar el bucle for
por primera vez.Si la condición no
evalúa como true
, el cuerpo del bucle no se ejecuta.
La expresión final se ejecuta al final de cada iteración a través del bucle. Por lo general, se usa para aumentar el identificador en uno.
Con más frecuencia, verás bucles for
iterando a través de arrays en versiones anteriores.
de código abierto. En estos casos, la condición especificada para continuar el bucle es una
recuento de iteraciones menor o igual que la longitud de la matriz que se itera
a través de él. La variable que se usa para rastrear el recuento de iteraciones actual se usa para buscar
el valor asociado con ese índice en el array, lo que permite que cada elemento de
el array sobre el que se debe actuar en orden:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
Este enfoque ha dejado de usarse y se lo reemplazó por enfoques más modernos para bucles a través de estructuras de datos iterables.
for
[...] of
[...]
Usa los bucles for
...of
... para iterar sobre los valores almacenados en un
estructura de datos iterables, como un array, un conjunto o un mapa.
Un bucle for
...of
... usa la palabra clave for
seguida de un conjunto de paréntesis.
que contiene una variable, seguida de of
y, luego, la estructura de datos que se itera
de nuevo. La variable puede ser una declaración realizada aquí con let
, const
, o
var
, una variable declarada anteriormente dentro del alcance actual, un objeto
propiedad o una instancia de
desestructuración de la tarea.
Contiene el valor del elemento que corresponde a la iteración actual
del bucle.
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
En este ejemplo, el uso de const
para myElement
funciona aunque myElement
sea
se les da un nuevo valor en cada iteración del bucle. Esto se debe a que las variables
declaradas con let
o const
tienen alcance en la sentencia de bloqueo dentro del
bucle. La variable se inicializa al comienzo de cada iteración y se quita en
el final de esa iteración.
for
... in
...
Usa los bucles for
...in
... para iterar sobre las propiedades enumerables de un objeto.
incluidas las propiedades heredadas que se pueden enumerar. Al igual que con un bucle for
...of
..., un
El bucle for
...in
... usa la palabra clave for
seguida de un conjunto de paréntesis
con una variable que contenga el valor de la clave de propiedad correspondiente
con la iteración actual del bucle. A esta variable le sigue el
in
y, luego, el objeto sobre el que se itera:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
Nuevamente, a pesar de que el valor de myKey
cambia con cada iteración del bucle,
puedes usar const
sin errores porque la variable se descarta eficazmente.
al final de cada iteración y, luego, se vuelven a crear al inicio.
El valor asociado con cada clave de propiedad no está disponible directamente para
Sintaxis de for
...in
.... Sin embargo, como el bucle tiene acceso a la clave de propiedad en
de cada iteración, puedes usar esa clave para "buscar" su valor:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
Las propiedades heredadas de constructores integrados no son enumerables, lo que significa que
for
...in
... no itera a través de las propiedades heredadas de Object
.
. Sin embargo, cualquier propiedad enumerable dentro del nombre
cadena de prototipos:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "protoProperty : true"
JavaScript proporciona métodos integrados para determinar si una propiedad es una
propiedad directa del objeto en lugar de una propiedad del prototipo del objeto
cadena: la estructura moderna
Object.hasOwn()
y los métodos Object.prototype.hasOwnProperty()
heredados Estos
evalúan si una propiedad especificada es heredada (o no declarada)
Se muestra true
solo para las propiedades inmediatas de un objeto especificado:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
if ( Object.hasOwn( myObject, myKey ) ) {
console.log( `${ myKey } : ${ myValue }` );
}
}
> "myProperty : true"
También hay tres métodos estáticos que muestran un array compuesto por un elemento
Claves enumerables del objeto (Object.keys()
), valores (Object.values()
) o
Pares clave-valor (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
Esto te permite iterar claves, valores o pares clave-valor de objetos (con desestructuración de tareas). sin incluir propiedades que sean propiedad del prototipo de ese objeto:
const myPrototype = { "protoProperty" : "Non-enumerable property value." };
const myObject = Object.create( myPrototype, {
myProperty: {
value: "Enumerable property value.",
enumerable: true
}
});
for ( const propKey of Object.keys( myObject ) ) {
console.log( propKey );
}
> "myProperty"
for ( const propValue of Object.values( myObject ) ) {
console.log( propValue );
}
> "Enumerable property value."
for ( const [ propKey, propValue ] of Object.entries( myObject ) ) {
console.log( `${ propKey } : ${ propValue }` );
}
> "myProperty : Enumerable property value."
forEach()
Los métodos forEach()
que proporciona Array
Mapa, Establecer,
y los constructores de NodeList proporcionan una abreviatura útil para iterar sobre un conjunto de datos.
en el contexto de una función de devolución de llamada. A diferencia de otras formas de bucle, un
el bucle creado con cualquier método forEach()
no se puede interrumpir mediante break
continue
forEach
es un método que pertenece al prototipo de cada estructura de datos. Cada forEach
de destino espera una función de devolución de llamada como argumento, aunque varían ligeramente entre
términos de los argumentos incluidos cuando se llama a esa función. Un segundo (opcional)
especifica un valor this
para usar como contexto de invocación del
función de devolución de llamada.
La función de devolución de llamada que se usa con Array.forEach
proporciona parámetros que contienen
El valor del elemento actual, el índice del elemento actual y el array en el que se invocó el método forEach
:
const myArray = [ true, false ];
myArray.forEach( ( myElement, i, originalArray ) => {
console.log( i, myElement, originalArray );
});
> 0 true Array(3) [ true, false ]
> 1 false Array(3) [ true, false ]
La función de devolución de llamada que se usa con Map.forEach
proporciona parámetros que contienen el
valor asociado con el elemento actual, la clave asociada con el elemento
y el Map en el que se invocó el método forEach
:
const myMap = new Map([
['myKey', true],
['mySecondKey', false ],
]);
myMap.forEach( ( myValue, myKey, originalMap ) => {
console.log( myValue, myKey, originalMap );
});
> true "myKey" Map { myKey → true, mySecondKey → false }
> false "mySecondKey" Map { myKey → true, mySecondKey → false }
Una devolución de llamada Set.forEach
incluye parámetros similares. Como el conjunto no tiene
o claves distintas de los valores, el segundo argumento proporciona una
es redundante, es un valor que se puede ignorar, para que la sintaxis sea coherente
otros métodos forEach
.
const mySet = new Set([ true, false ]);
mySet.forEach( ( myValue, myKey, originalSet ) => {
console.log( myValue, myKey, originalSet );
});
> true true Set [ true, false ]
> false false Set [ true, false ]
Iteradores
Un iterable es cualquier estructura de datos compuesta por elementos individuales que se pueden
e iterarse con respecto a los enfoques detallados anteriormente. Un iterador es un
objeto iterable que sigue el protocolo iterador, lo que significa que debe implementar
Un método next()
que avanza por los elementos que contiene uno a la vez
cada vez que se llama a ese método, de modo que se devuelve un objeto por cada
en un formato específico.
Las estructuras de datos iterables integradas de JavaScript (como
Array,
Mapa y
Set) no son iteradores en y de
pero todos heredan un método iterator
, al que se puede acceder con el
@@iterator
símbolo conocido,
que muestra un objeto iterador creado a partir de la estructura de datos iterable:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
Llamar al método next()
en un iterador recorre los elementos que contiene
contiene uno a la vez, y cada llamada muestra un objeto que contiene dos
propiedades: value
, que contiene el valor del elemento actual.
done
, un valor booleano que indica si el iterador pasó el último elemento en
la estructura de los datos. El valor de done
es true
solo cuando una llamada a next()
.
provoca un intento de acceso a un elemento más allá del último elemento de la
iterador.
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: undefined, done: true }
Funciones del generador
Usa la palabra clave function*
(ten en cuenta el asterisco) para declarar un generador
función o definir una expresión de función del generador:
function* myGeneratorFunction() { };
Al igual que los iteradores, las funciones del generador mantienen el estado. Llamar a un generator muestra un nuevo objeto Generator, pero no ejecuta el código en el cuerpo de la función:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
Los objetos generadores siguen el protocolo del iterador. El valor que cada llamada a
next()
en una función de generador que muestra está determinado por una expresión yield
.
lo que pausa la ejecución de la función del generador y devuelve el valor del
expresión que contiene la palabra clave yield
. Llamadas posteriores a next()
continúa la ejecución de la función, pausando en la siguiente expresión yield
y
para mostrar el valor asociado.
function* myGeneratorFunction() {
yield "My first yielded value.";
yield "My second yielded value.";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: "My first yielded value.", done: false }
myGeneratorObject.next();
> Object { value: "My second yielded value.", done: false }
Cuando se llama a next()
después de que no se especifican más valores mediante yield
,
return
o throw
(en caso de un error); el resto de la función
se ejecuta, y el objeto que se devuelve tiene un value
de undefined
y un done
propiedad de true
:
function* myGeneratorFunction() {
console.log( "Start of the generator function." );
yield "First";
console.log( "Second part of the generator function." );
yield "Second";
console.log( "Third part of the generator function." );
yield "Third";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> "Start of the generator function."
> Object { value: "First", done: false }
myGeneratorObject.next();
> "Second part of the generator function."
> Object { value: "Second", done: false }
myGeneratorObject.next();
> "Third part of the generator function."
> Object { value: "Third", done: false }
myGeneratorObject.next();
> Object { value: undefined, done: true }
Usa next()
solo en el objeto que muestra la función del generador, no en el
generador de salida. De lo contrario, cada llamada a la función del generador
crea un nuevo objeto generador:
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
Al igual que con cualquier función, la función de generador se detiene cuando encuentra una return
.
palabra clave. Luego, devuelve un objeto al contexto de invocación que contiene el
el valor que se muestra y una propiedad done
con el valor true
.
function* myGeneratorFunction() {
yield 1;
yield 2;
return 3;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next().done;
> Object { value: 1, done: false }
myGeneratorObject.next().done;
> Object { value: 2, done: false }
myGeneratorObject.next();
> Object { value: 3, done: true }
Una expresión yield
puede adoptar parte de la semántica de un identificador.
permitir la "comunicación" bidireccional desde la parte suspendida de la
generator. Cuando se pasa un valor al método next()
de un generador como
un argumento, reemplaza el valor asociado con el estado
Expresión yield
:
function* myGeneratorFunction() {
const firstYield = yield;
yield firstYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
Ten en cuenta que esto reemplaza toda la expresión asociada con el
yield
anterior y no reasigna solo el valor del yield
anterior a
el valor especificado en next()
:
function* myGeneratorFunction() {
const firstYield = yield;
const secondYield = yield firstYield + 100;
yield secondYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 10 ); // Can be thought of as changing the value of the `firstYield` variable to `10
> Object { value: 110, done: false }
myGeneratorObject.next( 20 ); // Can be thought of as changing the value of the `secondYield` variable to `20`, _not_ `20 + 100;`
> Object { value: 30, done: false }
Se ignora cualquier argumento que se pase a la primera llamada a next()
, ya que no hay
la expresión yield
anterior para aceptar ese valor. Al igual que con cualquier otra función,
los argumentos que se pasan a la llamada inicial a función del generador están disponibles en
el alcance del cuerpo de la función de generador:
function* myGeneratorFunction( startingValue ) {
let newValue = yield startingValue + 1;
newValue = yield newValue + 10;
yield startingValue + 20;
};
const myGeneratorObject = myGeneratorFunction( 2 );
myGeneratorObject.next( 1 );
> Object { value: 3, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
myGeneratorObject.next( 10 );
Object { value: 22, done: false }
El operador yield*
(ten en cuenta el asterisco) se usa con un elemento iterable, como
otra función generadora, para iterar y proporcionar cada valor a su operando
muestra lo siguiente:
function* mySecondaryGenerator() {
yield 2;
yield 3;
}
function* myGenerator() {
yield 1;
yield* mySecondaryGenerator();
yield 4;
return 5;
}
const myIterator = myGenerator();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: 4, done: false }
myIterator.next();
> Object { value: 5, done: true }
JavaScript asíncrono
Aunque JavaScript es básicamente síncrono, en ejecución, existen mecanismos que les permiten a los desarrolladores aprovechar el bucle de eventos para realizar las tareas asíncronas.
Promesas
Una promesa es un marcador de posición para un valor que no se conoce cuando la promesa se crear. Es un contenedor que dicta una operación asíncrona. Los términos en el que la operación se considera exitosa o fracaso, las medidas que se deben tomar en cualquier caso y el valor que se genera.
Crea una instancia de Promesa usando el operador new
con el Promise
integrado.
función de constructor. Este constructor acepta una función llamada executor.
como argumento. Esa función de ejecutor generalmente se usa para realizar una o más
acciones asíncronas y, luego, dictar los términos según los cuales se debe
se consideró completada correctamente o rechazada. Una promesa se define como pendiente.
mientras se ejecuta la función ejecutora. Después de que el ejecutor finaliza, aparece una promesa
se considera completado (o resuelto, en algunas fuentes de documentación) si
se completan la función de ejecutor y la acción asíncrona que realiza
con éxito y rechazada si la función ejecutora encuentra un error, o
la acción asíncrona que se realiza falla. Después de que se cumple una promesa o
rechazado, se considera resuelta.
const myPromise = new Promise( () => { });
El constructor llama a la función de ejecutor con dos argumentos. Esos argumentos son funciones que te permiten cumplir o rechazar manualmente la promesa:
const myPromise = new Promise( ( fulfill, reject ) => { });
Las funciones que se usan para cumplir o rechazar una promesa se llaman valor de la promesa como argumento (generalmente, un error por rechazo):
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was successful." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 10000);
});
myPromise;
> Promise { <state>: "pending" }
myPromise;
> Promise { <state>: "fulfilled", <value>: "This Promise was successful." }
Encadenamiento de promesas
Se puede actuar sobre el objeto Promise resultante mediante los métodos then()
, catch()
y
Métodos finally()
heredados del constructor de Promise. Cada uno de estos
muestra una promesa, en la que se puede actuar de inmediato con then()
,
catch()
o finally()
de nuevo, lo que te permite encadenar las promesas resultantes.
then()
proporciona dos funciones de devolución de llamada como argumentos. Usa la primera para completar
la promesa resultante, y el segundo en rechazarla. Ambos métodos aceptan un solo
que da su valor a la promesa resultante.
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise.then( successfulResult => console.log( successfulResult ), failedResult => console.error( failedResult ) );
> "This Promise was successful."
También puedes usar then()
para controlar solo el estado completado, y catch
para
manejar el estado rechazado. Llama a catch
con un solo argumento que contenga lo siguiente:
proporcionado en el método de rechazo de la promesa:
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = false;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise
.then( fulfilledResult => console.log(fulfilledResult ) )
.catch( rejectedResult => console.log( rejectedResult ) )
.finally( () => console.log( "The Promise has settled." ) );
> "Error: This Promise has been rejected."
> "The Promise has settled."
A diferencia de then
y catch
, que permiten que se ejecute una función de controlador cuando una promesa
se completa o se rechaza, una función pasada como argumento al finally
independientemente de si la promesa se cumplió o se rechazó.
Se llama a la función del controlador sin argumentos, ya que no está diseñada para
trabajar con los valores que se pasaron de la promesa, solo para ejecutar el código después de
La promesa se completó.
Simultaneidad
El constructor de Promise proporciona cuatro métodos para trabajar con varios métodos
promesas, con un objeto iterable que contenga objetos Promise. Estos
cada método devuelve una promesa, que se cumple o rechaza según el estado.
de las promesas que se le pasaron. Por ejemplo, Promise.all()
crea una promesa.
que se cumpla solo si se cumple cada promesa pasada a ese método:
const firstPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const secondPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const thirdPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const failedPromise = new Promise( ( fulfill, reject ) => reject( "Failed.") );
const successfulPromises = [ firstPromise, secondPromise, thirdPromise ];
const oneFailedPromise = [ failedPromise, ...successfulPromises ];
Promise.all( successfulPromises )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> Array(3) [ "Successful. ", "Successful. ", "Successful. " ]
Promise.all( oneFailedPromise )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> "Failed."
Los métodos de simultaneidad de las promesas son los siguientes:
Promise.all()
- Se entrega solo si se cumplen todas las promesas proporcionadas.
Promise.any()
- Se cumple si se cumple alguna de las promesas proporcionadas y solo se rechaza. si se rechazan todas las promesas.
Promise.allSettled()
- Se cumplen cuando se establecen las promesas, sin importar el resultado.
Promise.race()
- Se rechaza o se cumple en función del resultado de la primera promesa de liquidación, ignorando todas las promesas que se cumplieron más adelante.
async
/await
Cuando usas la palabra clave async
antes de una declaración de función.
o expresión de función, cualquier
valor que muestra la función se devuelve como una promesa cumplida que contiene ese
valor. Esto te permite ejecutar y administrar operaciones asíncronas con el mismo
como desarrollo síncrono.
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
La expresión await
pausa la ejecución de una función asíncrona mientras
se establece la promesa asociada. Después de que se establece la promesa, el valor de
La expresión await
es el valor cumplido o rechazado de la promesa.
async function myFunction() {
const myPromise = new Promise( ( fulfill, reject ) => { setTimeout( () => fulfill( "Successful. "), 5000 ); });
const myPromisedResult = await myPromise;
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "Successful."
Cualquier valor que no sea de promesa incluido en una expresión await
se muestra como un
Promesa cumplida:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
Verifica tus conocimientos
¿Qué tipo de bucle usas para iterar en una cantidad conocida?
do...while
for
while