JavaScript comum promete matéria que todos deveriam saber



Bom dia amigos

Apresento a você a tradução do artigo de Apal Shah, “Erros comuns de promessa de Javascript que todo iniciante deve conhecer e evitar .

JavaScript comum promete saber que todos devem conhecer


Gostaria de saber sobre esses erros quando estudei JavaScript e promessas.

Sempre que algum desenvolvedor me chama e reclama que seu código não está funcionando ou está sendo executado lentamente, primeiro presto atenção a esses erros. Quando comecei a programar há 4 anos, eu não os conhecia e estava acostumado a ignorá-los. No entanto, depois de ser atribuído a um projeto que processa cerca de um milhão de solicitações em alguns minutos, não tive escolha a não ser otimizar meu código (já que alcançamos um nível em que uma escala vertical adicional se tornou impossível).

Portanto, neste artigo, gostaria de falar sobre os erros mais comuns ao trabalhar com promessas em JS, às quais muitos não prestam atenção.

Erro # 1. Usando um bloco try / catch dentro de um Promise


Usar o bloco try / catch dentro da promessa é impraticável, porque se o seu código gerar um erro (dentro da promessa), ele será interceptado pelo manipulador de erros da própria promessa.

É disso que se trata:
new Promise((resolve, reject) => { try { const data = someFunction() //   resolve() } catch(e) { reject(e) } }) .then(data => console.log(data)) .catch(error => console.log(error)) 

Em vez disso, deixe o código manipular o erro fora da promessa:
 new Promise((resolve, reject) => { const data = someFunction() //   resolve(data) }) .then(data => console.log(data)) .catch(error => console.log(error)) 

Isso sempre funcionará, exceto conforme descrito abaixo.

Erro No. 2. Usando uma função assíncrona dentro de um Promise


Ao usar a função assíncrona, alguns efeitos colaterais desagradáveis ​​ocorrem dentro da promessa.

Suponha que você decida executar alguma tarefa assíncrona, adicione a palavra-chave "async" à promessa e seu código gera um erro. No entanto, agora você não pode lidar com esse erro com .catch () ou aguardar:
 //       new Promise(async() => { throw new Error('message') }).catch(e => console.log(e.message)) //        (async() => { try { await new Promise(async() => { throw new Error('message') }) } catch(e) { console.log(e.message) } })(); 

Toda vez que encontro uma função assíncrona dentro de uma promessa, tento separá-las. E recebo em 9 de 10 casos. No entanto, isso nem sempre é possível. Nesse caso, você não tem escolha a não ser usar o bloco try / catch dentro da promessa (sim, isso contradiz o primeiro erro, mas esta é a única saída):
 new Promise(async(resolve, reject) => { try { throw new Error('message') } catch(error) { reject(error) } }).catch(e => console.log(e.message)) //   async/await (async() => { try { await new Promise(async(resolve, reject) => { try { throw new Error('message') } catch(error) { reject(error) } }) } catch(e) { console.log(e.message) } })(); 

Erro número 3. Esqueça .catch ()


Esse é um desses erros que você nem suspeita existir até o início do teste. Ou, se você é ateu que não acredita em testes, seu código certamente trava na produção . Como a produção segue rigorosamente a lei de Murphy , que afirma: "Qualquer coisa que pode dar errado vai dar errado" (você pode traduzir isso: "Se algo pode dar errado, isso vai acontecer"); a analogia em russo é a "lei da maldade" - aprox.

Para tornar o código mais elegante, você pode quebrar a promessa em try / catch em vez de usar .then (). Catch ().

Erro nº 4. Não use Promise.all ()


Promise.all () é seu amigo.

Se você é um desenvolvedor profissional, provavelmente entende o que quero dizer. Se você tem várias promessas que não dependem uma da outra, é possível executá-las ao mesmo tempo. Por padrão, as promessas são executadas em paralelo; no entanto, se você precisar executá-las sequencialmente (usando aguardar), levará muito tempo. Promise.all () pode reduzir bastante a latência:
 const {promisify} = require('util') const sleep = promisify(setTimeout) async function f1() { await sleep(1000) } async function f2() { await sleep(2000) } async function f3() { await sleep(3000) } //   (async() => { console.time('sequential') await f1() await f2() await f3() console.timeEnd('sequential') //  6  })(); 

Agora com Promise.all ():
 (async() => { console.time('concurrent') await Promise.all([f1(), f2(), f3()]) console.timeEnd('concurrent') //  3  })(); 

Erro nº 5. Uso inadequado de Promise.race ()


Promise.race () nem sempre torna seu código mais rápido.

Pode parecer estranho, mas realmente é. Não estou dizendo que Promise.race () é um método inútil, mas você deve entender claramente por que está usando.

Por exemplo, você pode usar Promise.race () para executar o código após resolver qualquer uma das promessas. Mas isso não significa que a execução do código após as promessas começará imediatamente após a resolução de uma delas. Promise.race () esperará que todas as promessas sejam resolvidas e só então libere o fluxo:
 const {promisify} = require('util') const sleep = promisify(setTimeout) async function f1() { await sleep(1000) } async function f2() { await sleep(2000) } async function f3() { await sleep(3000) } (async() => { console.time('race') await Promise.race([f1(), f2(), f3()]) })(); process.on('exit', () => { console.timeEnd('race') //  3 ,    ! }) 

Erro nº 6. Abuso de promessas


As promessas tornam o código mais lento, portanto, não abuse delas.

Muitas vezes, é necessário ver os desenvolvedores usando uma longa cadeia .then () para melhorar o código. Você não terá tempo de piscar de olhos, pois essa corrente se torna muito longa. Para verificar visualmente as conseqüências negativas de tal situação, é necessário (mais adiante, vou desviar um pouco do texto original para descrever o processo com mais detalhes do que no artigo - aprox. Trans):

1) crie um arquivo script.js com o seguinte conteúdo (com promessas extras):
 new Promise((resolve) => { //  ,    const user = { name: 'John Doe', age: 50, } resolve(user) }).then(userObj => { const {age} = userObj return age }).then(age => { if(age > 25) { return true } throw new Error('Age is less than 25') }).then(() => { console.log('Age is greater than 25') }).catch(e => { console.log(e.message) }) 

2) abra a linha de comando (para usuários do Windows: para abrir a linha de comando na pasta com o arquivo desejado, mantenha pressionada a tecla Shift, clique com o botão direito do mouse, selecione "Abrir janela de comando"), execute o script.js usando o seguinte comando (o Nó deve estar instalado. js):
 node --trace-events-enabled script.js 

3) Node.js cria um arquivo de log (no meu caso, node_trace.1.txt) na pasta com o script;

4) abra o Chrome (porque ele funciona apenas nele), digite "chrome: // tracing" na barra de endereço;

5) clique em Carregar, carregue o arquivo de log criado pelo Node.js;

6) abra a guia Promessa.

Vemos algo como o seguinte:


Blocos verdes são promessas, cada uma das quais leva vários milissegundos para ser concluída. Portanto, quanto mais promessas serão, mais tempo serão cumpridas.

Reescrevemos script.js:
 new Promise((resolve, reject) => { const user = { name: 'John Doe', age: 50, } if(user.age > 25) { resolve() } else { reject('Age is less than 25') } }).then(() => { console.log('Age is greater than 25') }).catch(e => { console.log(e.message) }) 

Repita o "traço".

Vemos o seguinte:


Existem menos blocos verdes (promessas), o que significa que o tempo de execução do código foi reduzido.

Portanto, você deve usar várias promessas apenas se precisar executar algum código assíncrono.

Obrigado pela atenção. Tenham um bom final de semana! Ficarei feliz em quaisquer comentários.

Source: https://habr.com/ru/post/pt484466/


All Articles