Fluxo de controle é a ordem em que o intérprete JavaScript é executado declarações. Se um script não inclui instruções que alteram seu fluxo, ele é executada do início ao fim, uma linha de cada vez. As estruturas de controle são usada para determinar se um conjunto de instruções é executado ou não com base em uma um conjunto de critérios definido, executar um conjunto de instruções repetidamente ou interromper uma sequência de instruções.
Instruções condicionais
As instruções condicionais determinam se o código deve ser executado com base em
mais condições. Uma instrução condicional executa o código que ela contém se o
a condição associada (ou conjunto de condições) é avaliada como true
. Caso contrário, o
será ignorado.
if
...else
else
Uma instrução if
avalia uma condição dentro dos parênteses correspondentes que
seguir. Se a condição dentro dos parênteses for avaliada como true
, o
Instrução ou block statement
que segue os parênteses correspondentes é executado:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
Se a condição entre parênteses for avaliada como false
, a instrução que
segue, ele será ignorado:
if ( false ) console.log( "True." );
Uma palavra-chave else
imediatamente após uma instrução if
e a
instrução executada condicionalmente, especifica a instrução a ser executada se o
A condição if
é avaliada como false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
Para encadear várias instruções if
, faça o
instrução condicionalmente executada após else
outra instrução if
:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
Recomendamos o uso da sintaxe de instrução de bloco após condicionais para
melhorar a legibilidade, mas as cláusulas else if
geralmente são uma exceção a isso:
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 ternário
if
executa uma instrução condicionalmente. O operador ternário (mais precisamente
mas menos conhecida como operador condicional ternário) é uma abreviação usada
para executar condicionalmente uma expressão. Como o nome indica, a função
é o único operador JavaScript que usa três operandos:
- Uma condição a ser avaliada, seguida por um ponto de interrogação (
?
). - A expressão a ser executada se a condição for avaliada como
true
, seguida por uma dois pontos (:
). - A expressão a ser executada se a condição for avaliada como
false
.
É usado com frequência para definir ou transmitir condicionalmente um valor:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
...case
Use a instrução switch
para comparar o valor de uma expressão a uma lista de
valores potenciais definidos usando uma ou mais palavras-chave case
. Essa sintaxe é
incomuns, pois vêm de algumas das primeiras decisões de design do JavaScript.
A sintaxe switch
...case
usa a palavra-chave switch
, seguida por uma expressão para
será avaliado entre parênteses, seguidos por um par correspondente de chaves.
O corpo de switch
pode conter palavras-chave case
, geralmente uma ou mais,
seguido de uma expressão ou valor e dois-pontos (:
).
Quando o intérprete atinge um case
com um valor correspondente à expressão que está sendo
avaliado entre parênteses após a palavra-chave switch
, ele executa qualquer
instruções que seguem a cláusula case
:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
Todas as instruções após o case
correspondente são executadas, mesmo se forem
em uma instrução de bloco.
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
Uma armadilha do uso de switch…case
é que, depois que uma correspondência é encontrada, a
O intérprete de JavaScript executa qualquer instrução que siga o case
correspondente,
mesmo as que estão dentro de outras cláusulas case
. Isso é chamado de "cair", ao
próximas case
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
Para evitar falhas, encerre cada caso com a palavra-chave break
, que
interrompe imediatamente a avaliação do corpo switch
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
Se nenhum case
corresponder ao valor condicional, o switch
selecionará o default
.
se houver:
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."
No entanto, a queda também se aplica a default
, possivelmente levando a
resultados inesperados. Para corrigir isso, encerre sua instrução default
com break
,
ou colocá-la por último na 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.
Como as cláusulas case
não exigem uma
instrução de bloco para agrupamento
várias instruções, as cláusulas case
e default
não criam
escopo léxico por si só:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
Para gerenciar o escopo, use instruções de bloco:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
Loops e iteração
As repetições permitem repetir um conjunto de instruções enquanto uma condição for atendida. Ou até que uma condição seja atendida. Usar repetições para executar um conjunto de instruções número de vezes, até que um resultado específico seja alcançado ou até que o intérprete chega ao final de uma estrutura de dados iterável (por exemplo, o elemento final em uma matriz, mapa ou conjunto, a propriedade final de um objeto ou o último caractere em uma string).
As repetições interrompem "de cima para baixo" de execução de um script iterando as sobre um conjunto de instruções até que uma ou mais condições sejam atendidas ou atendidos, dependendo da sintaxe usada para criar o loop. Após o término do loop, a execução continua para as instruções que a seguem. No exemplo a seguir, as instruções no corpo do loop são executadas três vezes antes da intérprete segue em frente:
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."
Se as condições não puderem ser atendidas durante a execução da repetição, ela continuará indefinidamente. Essas loops infinitas são um problema comum de programação que pode fazer com que a linha de execução principal para pausar indefinidamente ou até mesmo travar uma guia do navegador.
O exemplo a seguir é executado enquanto o valor booleano true
permanecer
true
: Como os valores booleanos são imutáveis,
isso cria um loop infinito.
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
Evite deixar loops infinitos no código de produção. Se você criar, sem querer, durante o desenvolvimento, poderá corrigi-lo fechando a guia do navegador em execução atualizar seu código para que o loop não seja mais infinito e reabrir página.
while
Uma repetição while
é criada usando a palavra-chave while
seguida por um par de
parênteses correspondentes que contêm uma condição a ser avaliada. Se o valor especificado
inicialmente é avaliada como true
, a instrução (ou
block statement) que segue
parênteses são executados. Caso contrário, a repetição nunca será executada. Após cada
iteração, a condição será reavaliada e, se ainda for true
, a repetição
se repete.
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
Se o intérprete encontrar uma instrução continue
em uma repetição while
, ela vai interromper essa
iteração, reavalia a condição e continua o loop, se possível:
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."
Se o intérprete encontrar uma instrução break
em uma repetição while
, essa iteração
é interrompida e a condição não é reavaliada, permitindo que o intérprete siga em frente:
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."
É possível usar while
para iterar um número especificado de vezes, como mostrado nas
exemplo anterior, mas o caso de uso mais comum de while
é uma repetição de
comprimento indeterminado:
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
é uma variante da repetição while
em que a condição
A avaliação acontece no fim de cada iteração do loop. Isso significa que
o corpo do loop é sempre executado pelo menos uma vez.
Para criar uma repetição do
...while
, use a palavra-chave do
seguida pela instrução
(ou declaração de bloqueio)
executada em cada iteração da repetição. Imediatamente após essa instrução, adicione
while
e parênteses correspondentes que contêm a condição a ser avaliada. Quando
essa condição não for mais avaliada como true
, o loop será encerrado.
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
Como acontece com uma repetição while
, o caso de uso mais comum para do
...while
é uma repetição de
comprimento indeterminado:
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
Use repetições for
para iterar até uma quantidade conhecida. Nas bases de código legadas, isso era
usada com frequência para iterar os elementos de uma matriz.
Para criar uma repetição for
, use a palavra-chave for
, seguida por um conjunto de parênteses.
que aceite as três expressões seguintes em ordem e separadas por
Ponto e vírgula:
- Uma expressão a ser avaliada quando a repetição começa
- Condição que determina se o loop deve continuar.
- Uma expressão a ser executada na conclusão de cada loop.
Depois desses parênteses, adicione a instrução (normalmente uma block statement) sejam executada durante a repetição.
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
A primeira expressão inicializa uma variável que atua como contador. Isso
é avaliada uma vez, antes da primeira iteração do loop. Você pode
inicialize essa variável usando let
(ou var
, historicamente) como qualquer outro
e o escopo dela é o corpo do loop. Essas variáveis podem ter
identificador válido, mas muitas vezes são chamados de i
para "iteração". ou "índice".
Isso parece contradizer as decisões estabelecidas
práticas recomendadas para nomes de identificadores previsíveis,
mas a convenção está bem estabelecida o suficiente para ser clara para outros desenvolvedores da
rapidamente. Como as coleções indexadas não são indexadas,
essas variáveis quase sempre têm um valor inicial de 0
.
Assim como em outras formas de repetição, a condição é uma expressão que determina
se o loop precisa ser executado. Ele é mais usado para definir um valor
vinculado ao contador de iterações. O intérprete avalia a condição antes
ao executar a repetição for
pela primeira vez.Se a condição não
avaliar como true
, o corpo da repetição não será executado.
A expressão final é executada ao final de cada iteração pelo loop. Geralmente, é usado para incrementar o identificador em um.
É mais comum encontrar repetições for
iterando matrizes em matrizes mais antigas.
bases de código. Nesses casos, a condição especificada para continuar o loop é uma
contagem de iterações menor ou igual ao comprimento da matriz que está sendo iterada
por A variável usada para rastrear a contagem de iteração atual é usada para procurar
o valor associado a esse índice na matriz, permitindo que cada elemento em
a matriz a ser executada na ordem:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
Essa abordagem deixou de ser usada em favor de abordagens mais modernas para repetir estruturas de dados iteráveis.
for
[...] of
[...]
Use repetições for
...of
... para iterar nos valores armazenados em uma
estrutura de dados iterável, como uma matriz, conjunto ou mapa.
Uma repetição for
...of
... usa a palavra-chave for
seguida por um conjunto de parênteses.
contendo uma variável, seguida por of
, e a estrutura de dados que está sendo iterada
de novo. A variável pode ser uma declaração realizada aqui usando let
, const
ou
var
, uma variável declarada anteriormente no escopo atual, um objeto
ou uma instância do
desestruturar atribuição.
Ele contém o valor do elemento que corresponde à iteração atual
do loop.
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
Neste exemplo, o uso de const
para myElement
funciona mesmo que myElement
seja
recebe um novo valor em cada iteração do loop. Isso ocorre porque as variáveis
declarados com let
ou const
têm o escopo da instrução de bloco dentro do
repetição. A variável é inicializada no início de cada iteração e removida
ao fim dessa iteração.
for
...in
...
Use repetições for
...in
... para iterar as propriedades enumeráveis de um objeto.
incluindo propriedades herdadas enumeráveis. Assim como acontece com uma repetição for
...of
..., uma
A repetição for
...in
... usa a palavra-chave for
seguida por um conjunto de parênteses.
que contém uma variável que contém o valor da chave de propriedade correspondente
com a iteração atual do loop. Essa variável é seguida pelo
Palavra-chave in
, em seguida, o objeto que está sendo iterado:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
Novamente, apesar do valor de myKey
mudar a cada iteração da repetição,
é possível usar const
sem erro porque a variável é efetivamente descartada
ao final de cada iteração e recriadas no início.
O valor associado a cada chave de propriedade não está diretamente disponível para o
Sintaxe de for
...in
.... No entanto, como o loop tem acesso à chave de propriedade
cada iteração, você pode usar essa chave para "procurar" seu valor:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
As propriedades herdadas de construtores integrados não são enumeráveis, o que significa que
for
...in
... não itera nas propriedades herdadas do Object
construtor. No entanto, as propriedades enumeráveis dentro do
protótipo cadeia estão incluídos:
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"
O JavaScript fornece métodos integrados para determinar se uma propriedade é uma
propriedade direta do objeto em vez de uma propriedade no protótipo do objeto
rede: o modelo moderno
Object.hasOwn()
e métodos Object.prototype.hasOwnProperty()
legados. Esses
avaliam se uma propriedade especificada é herdada (ou não declarada),
retornando true
apenas para as propriedades imediatas de um 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"
Há também três métodos estáticos que retornam uma matriz composta por uma
Chaves enumeráveis (Object.keys()
), valores (Object.values()
) ou do objeto
pares de chave-valor (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
Isso permite iterar chaves, valores ou pares de chave-valor de Objetos (usando o atribuição de desestruturação) sem incluir propriedades pertencentes ao protótipo desse 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()
Os métodos forEach()
fornecidos pela Array,
Mapa, Definir,
e os construtores NodeList oferecem uma forma abreviada útil de iterar em uma linha
no contexto de uma função de callback. Ao contrário de outras formas de loop, uma
A repetição criada com qualquer método forEach()
não pode ser interrompida usando break
ou
continue
forEach
é um método do protótipo de cada estrutura de dados. Cada forEach
método espera uma função de retorno de chamada como um argumento, embora eles variem um pouco em
termos dos argumentos incluídos quando essa função é chamada. Um segundo, opcional
especifica um valor this
a ser usado como o contexto de invocação do
função de callback.
A função de callback usada com Array.forEach
fornece parâmetros que contêm
o valor do elemento atual, o índice do elemento atual e a matriz em que o método forEach
foi invocado:
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 ]
A função de callback usada com Map.forEach
fornece parâmetros que contêm o
valor associado ao elemento atual, a chave associada ao elemento atual
e o mapa em que o método forEach
foi invocado:
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 }
Um callback Set.forEach
inclui parâmetros semelhantes. Como o Set não tem
índices ou chaves diferentes dos valores, o segundo argumento fornece uma
valor redundante e ignorável, estritamente para manter a sintaxe consistente com o
outros 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
Um iterável é qualquer estrutura de dados composta por elementos individuais que podem ser
iterado usando as abordagens detalhadas anteriormente. Um iterador é uma
objeto iterável que segue o protocolo de iterador, o que significa que ele deve implementar
um método next()
que avança pelos elementos que contém, um de cada vez,
sempre que esse método for chamado, retornando um objeto para cada ação
elemento em um formato específico.
As estruturas de dados iteráveis integradas do JavaScript (como
Matriz,
Map e
Set) não são iteradores em e de
mas todos herdam um método iterator
, que pode ser acessado usando o
@@iterator
Símbolo conhecido,
que retorna um objeto iterador criado a partir da estrutura de dados iterável:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
Chamar o método next()
em um iterador percorre os elementos que ele
contém um por vez, com cada chamada retornando um objeto contendo duas
propriedades: value
, que contém o valor do elemento atual, e
done
, um booleano que informa se o iterador passou o último elemento em
na estrutura de dados. O valor de done
é true
somente quando uma chamada para next()
resulta em uma tentativa de acessar um elemento além do último na
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 }
Funções gerador
Use a palavra-chave function*
(observe o asterisco) para declarar um gerador
ou defina uma expressão de função geradora:
function* myGeneratorFunction() { };
Assim como os iteradores, as funções geradoras mantêm o estado. Chamar um função generator retorna um novo objeto Generator, mas não retorna imediatamente execute o código no corpo da função:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
Os objetos gerador seguem o protocolo de iterador. O valor de cada chamada
O next()
em uma função geradora retorna é determinado por uma expressão yield
.
que pausa a execução da função geradora e retorna o valor do
expressão que contém a palavra-chave yield
. Chamadas posteriores para next()
continua a execução da função, pausando na próxima expressão yield
e
retornando o valor associado.
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 }
Quando next()
é chamado depois que nenhum outro valor é especificado usando yield
,
return
ou throw
(no caso de um erro), o restante da função
O corpo é executado e o objeto retornado tem um value
de undefined
e um done
propriedade 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 }
Use next()
somente no objeto que a função geradora retornar, não no
função geradora em si. Caso contrário, cada chamada à função gerador
cria um novo objeto gerador:
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
Como acontece com qualquer função, a função do gerador é interrompida quando encontra um return
.
palavra-chave. Em seguida, ele retorna um objeto para o contexto de invocação que contém o
valor retornado e uma propriedade done
com o 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 }
Uma expressão yield
pode assumir algumas das semânticas de um identificador,
permitindo a "comunicação" bidirecional de e para a parte suspensa do
função geradora. Quando um valor é transmitido para o método next()
de um gerador como
um argumento, ela substitui o valor associado ao prefixo anterior,
Expressão 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 }
Lembre-se de que isso substitui toda a expressão associada ao
yield
anterior e não apenas reatribui o valor do yield
anterior ao
o valor especificado em 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 }
Qualquer argumento transmitido para a primeira chamada para next()
é ignorado, porque não há
expressão yield
anterior para aceitar esse valor. Como em qualquer outra função,
os argumentos passados para a chamada da função do gerador inicial estão disponíveis em todo
escopo do corpo da função geradora:
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 }
O operador yield*
(observe o asterisco) é usado com um iterável, como
outra função de gerador, para iterar e gerar cada valor no operando dele
retorna:
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 assíncrono
Embora o JavaScript seja fundamentalmente síncrono em execução, há mecanismos que permitem aos desenvolvedores aproveitar o loop de eventos para realizar tarefas assíncronas.
Promessas
Uma promessa é um marcador de posição para um valor que não é conhecido quando a promessa é criados. É um contêiner que dita uma operação assíncrona, os termos quais a operação é considerada um sucesso ou uma falha, as ações a serem tomadas em qualquer um dos casos e o valor resultante.
Criar uma instância de promessa usando o operador new
com o Promise
integrado
função construtora. Esse construtor aceita uma função chamada executor.
como argumento. Essa função de executor é normalmente usada para executar um ou mais
ações assíncronas e, em seguida, ditar os termos pelos quais a promessa deve ser
considerados concluídos ou rejeitados. Uma promessa é definida como pendente.
enquanto a função do executor está em execução. Depois que o executor termina, uma promessa
é considerada realizada (ou resolvida, em algumas fontes de documentação) se
a função do executor e a ação assíncrona que ela executa são concluídas
com sucesso e rejected se a função do executor encontrar um erro ou
a ação assíncrona que está sendo realizada falhará. Depois que uma promessa for cumprida ou
for rejeitada, ela será considerada resolvida.
const myPromise = new Promise( () => { });
O construtor chama a função do executor com dois argumentos. Esses argumentos são funções que permitem cumprir ou rejeitar manualmente a promessa:
const myPromise = new Promise( ( fulfill, reject ) => { });
As funções usadas para atender ou rejeitar uma promessa são chamadas com o resultado valor da promessa como um argumento (normalmente, um erro de rejeição):
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." }
Encadeamento de promessas
O objeto de promessa resultante pode ser usado usando os operadores then()
, catch()
e
Métodos finally()
herdados do construtor de promessas. Cada um desses
retorna uma promessa, que pode ser executada imediatamente com then()
.
catch()
ou finally()
novamente, o que permite encadear as promessas resultantes.
then()
fornece duas funções de callback como argumentos. Use o primeiro para atender
a promessa resultante e o segundo a rejeitá-la. Os dois métodos aceitam um único
que fornece o valor da promessa 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."
Também é possível usar then()
para processar apenas o estado preenchido e catch
para
para processar o estado rejeitado. Chame catch
com um único argumento contendo o
valor fornecido no método de rejeição da promessa:
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."
Ao contrário de then
e catch
, que permitem que uma função de gerenciador seja executada quando uma promessa
for atendida ou rejeitada, uma função transmitida como um argumento para a finally
é chamado independentemente de a promessa ter sido atendida ou rejeitada.
A função de manipulador é chamada sem argumentos, porque ela não se destina a
trabalham com os valores passados da promessa, somente para executar o código após a
A promessa foi concluída.
Simultaneidade
O construtor de promessas fornece quatro métodos para trabalhar com vários métodos
Promessas usando um iterable contendo objetos de promessa. Esses
métodos retornam uma promessa, que é atendida ou rejeitada com base no estado.
das promessas passadas a ela. Promise.all()
, por exemplo, cria uma promessa
que será cumprida somente se todas as promessas passadas a esse método forem cumpridas:
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."
Os métodos de simultaneidade de promessas são os seguintes:
Promise.all()
- Cumprida apenas se todas as promessas fornecidas forem cumpridas.
Promise.any()
- Cumprido se qualquer uma das promessas fornecidas for cumprida, apenas recusada se todas as promessas forem recusadas.
Promise.allSettled()
- Cumprida quando as promessas são resolvidas, independentemente do resultado.
Promise.race()
- Rejeitada ou atendida com base no resultado da primeira promessa a ser resolvida, ignorando todas as promessas resolvidas depois.
async
/await
Quando você usa a palavra-chave async
antes de uma declaração de função
ou expressão da função, qualquer
valor retornado pela função é retornado como uma promessa cumprida que contém
. Isso permite executar e gerenciar operações assíncronas usando a mesma
fluxos de trabalho como desenvolvimento síncrono.
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
A expressão await
pausa a execução de uma função assíncrona enquanto
a promessa associada é resolvida. Depois que a promessa for resolvida, o valor
a expressão await
é o valor preenchido ou rejeitado da promessa.
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."
Qualquer valor não promessa incluído em uma expressão await
é retornado como uma
Promessa cumprida:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
Teste seu conhecimento
Que tipo de repetição você usa para iterar sobre uma quantidade conhecida?
do...while
while
for