diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md index 5a00f348f..05e16aee4 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md @@ -1,6 +1,6 @@ -The short answer is: **no, they are not the equal**: +A resposta breve é: **não, eles não são iguais**: -The difference is that if an error happens in `f1`, then it is handled by `.catch` here: +A diferença é que se um erro ocorrer em `f1` ele será tratado pelo `.catch` neste caso: ```js run promise @@ -8,13 +8,13 @@ promise .catch(f2); ``` -...But not here: +...Mas não neste: ```js run promise .then(f1, f2); ``` -That's because an error is passed down the chain, and in the second code piece there's no chain below `f1`. +Isso é devido ao erro ser propagado pela cadeia, e no segundo código não há cadeia após `f1`. -In other words, `.then` passes results/errors to the next `.then/catch`. So in the first example, there's a `catch` below, and in the second one -- there isn't, so the error is unhandled. +Em outras palavras, `.then` passa resultados/erros para o próximo `.then/catch`. Então, no primeiro exemplo, há um `catch` em seguida, e no segundo exemplo não há, então o erro não é tratado. diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md index cefca60aa..c9899d570 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md @@ -1,6 +1,6 @@ -# Promise: then versus catch +# Promessa: then versus catch -Are these code fragments equal? In other words, do they behave the same way in any circumstances, for any handler functions? +Estes fragmentos de código são iguais? Em outras palavras, eles se comportam da mesma maneira, em quaisquer circunstâncias, para qualquer função tratadora? ```js promise.then(f1).catch(f2); diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 9e560d67d..c8e10ae1f 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -1,13 +1,13 @@ -# Promises chaining +# Encadeamento de promessas -Let's return to the problem mentioned in the chapter : we have a sequence of asynchronous tasks to be done one after another. For instance, loading scripts. How can we code it well? +Vamos retornar ao problema mencionado no capítulo : temos uma sequência de tarefas assíncronas a serem executadas uma após a outra — por exemplo, o carregamento de scripts. Como podemos codificar isso bem? -Promises provide a couple of recipes to do that. +Promessas proveem algumas receitas para isso. -In this chapter we cover promise chaining. +Neste capítulo, vamos cobrir o encadeamento de promessas. -It looks like this: +Ele se parece com isto: ```js run new Promise(function(resolve, reject) { @@ -32,43 +32,25 @@ new Promise(function(resolve, reject) { }); ``` -The idea is that the result is passed through the chain of `.then` handlers. +A ideia é que o resultado seja passado através de uma cadeia de tratadores `.then`. -Here the flow is: -1. The initial promise resolves in 1 second `(*)`, -2. Then the `.then` handler is called `(**)`. -3. The value that it returns is passed to the next `.then` handler `(***)` -4. ...and so on. +O fluxo é o seguinte: +1. A promessa inicial é resolvida em 1 segundo `(*)`, +2. Então o tratador de `.then` é chamado `(**)`. +3. O valor retornado por ele é passado ao próximo tratador de `.then` `(***)` +4. ...e assim por diante. -As the result is passed along the chain of handlers, we can see a sequence of `alert` calls: `1` -> `2` -> `4`. +Como o resultado é passado através da cadeia de tratadores, podemos observar a sequência de chamadas `alert`: `1` -> `2` -> `4`. ![](promise-then-chain.svg) -The whole thing works, because a call to `promise.then` returns a promise, so that we can call the next `.then` on it. +A coisa toda funciona pois a chamada ao `promise.then` retorna uma promessa, assim podemos chamar o próximo `.then` nesse retorno. -When a handler returns a value, it becomes the result of that promise, so the next `.then` is called with it. +Quando um tratador retorna um valor, ele se torna o resultado da promessa, então o próximo `.then` é chamado com ele. -To make these words more clear, here's the start of the chain: +**Um erro clássico de novatos: tecnicamente, podemos chamar vários `.then` em uma única promessa. Isso não é encadeamento.** -```js run -new Promise(function(resolve, reject) { - - setTimeout(() => resolve(1), 1000); - -}).then(function(result) { - - alert(result); - return result * 2; // <-- (1) - -}) // <-- (2) -// .then… -``` - -The value returned by `.then` is a promise, that's why we are able to add another `.then` at `(2)`. When the value is returned in `(1)`, that promise becomes resolved, so the next handler runs with the value. - -**A classic newbie error: technically we can also add many `.then` to a single promise. This is not chaining.** - -For example: +Por exemplo: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); @@ -90,23 +72,23 @@ promise.then(function(result) { }); ``` -What we did here is just several handlers to one promise. They don't pass the result to each other, instead they process it independently. +O que fizemos aqui é apenas utilizar uma série de tratadores em uma promessa. Eles não passam o resultado uns aos outros; pelo contrário, eles o processam de maneira independente. -Here's the picture (compare it with the chaining above): +Aqui está uma imagem (compare-a com a cadeia acima): ![](promise-then-many.svg) -All `.then` on the same promise get the same result -- the result of that promise. So in the code above all `alert` show the same: `1`. +Todos os `.then` na mesma promessa obtêm o mesmo resultado -- o resultado dessa promessa. Então no código acima todas as chamadas `alert` mostrarão o mesmo: `1`. -In practice we rarely need multiple handlers for one promise. Chaining is used much more often. +Na prática, raramente precisamos de múltiplos tratadores para uma promessa. O encadeamento é utilizado com mais frequência. -## Returning promises +## Retornando promessas -Normally, a value returned by a `.then` handler is immediately passed to the next handler. But there's an exception. +Um tratador "handler", utilizado em `.then(handler)` pode criar e retornar uma promessa. -If the returned value is a promise, then the further execution is suspended until it settles. After that, the result of that promise is given to the next `.then` handler. +Nessa caso, tratadores seguintes aguardarão até que essa seja estabelecida, e então pegarão o seu resultado. -For instance: +Por exemplo: ```js run new Promise(function(resolve, reject) { @@ -137,16 +119,16 @@ new Promise(function(resolve, reject) { }); ``` + +Aqui o primeiro `.then` exibe `1` e retorna `new Promise(…)` na linha `(*)`. Após 1 segundo ele é resolvido, e o resultado (o argumento de `resolve`, no caso é `result * 2`) é passado ao tratador do segundo `.then`. O tratador está na linha `(**)`, ele exibe `2` e faz a mesma coisa. -Here the first `.then` shows `1` returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result*2`) is passed on to handler of the second `.then` in the line `(**)`. It shows `2` and does the same thing. - -So the output is again 1 -> 2 -> 4, but now with 1 second delay between `alert` calls. +Então a saída é a mesma que no exemplo anterior: 1 -> 2 -> 4, mas agora com 1 segundo de atraso entre as chamadas `alert`. -Returning promises allows us to build chains of asynchronous actions. +Retornar promessas nos permite construir um encadeamento de ações assíncronas. -## Example: loadScript +## Exemplo: loadScript -Let's use this feature with `loadScript` to load scripts one by one, in sequence: +Vamos utilizar esta funcionalidade com o `loadScript` "promisified", definido em [previous chapter](info:promise-basics#loadscript), para carregar scripts um a um, em sequência: ```js run loadScript("/article/promise-chaining/one.js") @@ -157,40 +139,40 @@ loadScript("/article/promise-chaining/one.js") return loadScript("/article/promise-chaining/three.js"); }) .then(function(script) { - // use functions declared in scripts - // to show that they indeed loaded + // usando funções declaradas nos scripts + // para mostrar que de fato foram carregados one(); two(); three(); }); ``` -This code can be made bit shorter with arrow functions: +Esse código pode ser resumido utilizando arrow functions: ```js run loadScript("/article/promise-chaining/one.js") .then(script => loadScript("/article/promise-chaining/two.js")) .then(script => loadScript("/article/promise-chaining/three.js")) .then(script => { - // scripts are loaded, we can use functions declared there + // scripts já carregados, podemos utilizar funções declaradas neles one(); two(); - three(); + // three() }); ``` -Here each `loadScript` call returns a promise, and the next `.then` runs when it resolves. Then it initiates the loading of the next script. So scripts are loaded one after another. +Aqui cada chamada `loadScript` retorna uma promessa, e o próximo `.then` é executado quando ela é resolvida. Então, é iniciado o carregamento do próximo script. Assim, os scripts são carregados um após o outro. -We can add more asynchronous actions to the chain. Please note that code is still "flat", it grows down, not to the right. There are no signs of "pyramid of doom". +Podemos adicionar mais ações assíncronas à cadeia. Por favor note que o código ainda está "flat" — ele cresce para baixo, não para direita. Não há sinais da "pyramid of doom". -Please note that technically we can add `.then` directly to each `loadScript`, like this: +Tecnicamente, poderíamos chamar `.then` diretamente em cada `loadScript`, desta maneira: ```js run loadScript("/article/promise-chaining/one.js").then(script1 => { loadScript("/article/promise-chaining/two.js").then(script2 => { loadScript("/article/promise-chaining/three.js").then(script3 => { - // this function has access to variables script1, script2 and script3 + // esta função tem acesso às variáveis script1, script2 e script3 one(); two(); three(); @@ -199,21 +181,19 @@ loadScript("/article/promise-chaining/one.js").then(script1 => { }); ``` -This code does the same: loads 3 scripts in sequence. But it "grows to the right". So we have the same problem as with callbacks. +Esse código faz o mesmo: carrega 3 scripts em sequência. Porém ele "cresce para direita". Então temos o mesmo problema das callbacks. -People who start to use promises sometimes don't know about chaining, so they write it this way. Generally, chaining is preferred. +Pessoas que iniciam a usar promessas às vezes não conhecem o encadeamento, então elas escrevem código dessa maneira. Geralmente, o encadeamento é preferido. -Sometimes it's ok to write `.then` directly, because the nested function has access to the outer scope. In the example above the most nested callback has access to all variables `script1`, `script2`, `script3`. But that's an exception rather than a rule. +Às vezes, é ok escrever `.then` diretamente, pois funções aninhadas possuem acesso ao escopo exterior. No exemplo acima, a callback mais aninhada possui acesso a todas as variáveis `script1`, `script2`, `script3`. Mas isso é uma exceção ao invés de ser uma regra. ````smart header="Thenables" -To be precise, `.then` may return an arbitrary "thenable" object, and it will be treated the same way as a promise. - -A "thenable" object is any object with a method `.then`. +Para ser preciso, um tratador pode não retornar exatamente uma promessa, mas um objeto conhecido por "thenable" - um objeto arbitrário que possui um método `.then`. Ele vai ser tratado da mesma maneira que uma promessa. -The idea is that 3rd-party libraries may implement "promise-compatible" objects of their own. They can have extended set of methods, but also be compatible with native promises, because they implement `.then`. +A ideia é que bibliotecas de terceiros possam implementar seus próprios objetos "compatíveis com promessas". Eles podem possuir um conjunto maior de métodos, mas também ser compatíveis com promessas nativas, pois eles implementam `.then`. -Here's an example of a thenable object: +Aqui está um exemplo de um objeto "thenable": ```js run class Thenable { @@ -222,79 +202,81 @@ class Thenable { } then(resolve, reject) { alert(resolve); // function() { native code } - // resolve with this.num*2 after the 1 second + // resolve com this.num*2 depois de 1 segundo setTimeout(() => resolve(this.num * 2), 1000); // (**) } } new Promise(resolve => resolve(1)) .then(result => { +*!* return new Thenable(result); // (*) +*/!* }) - .then(alert); // shows 2 after 1000ms + .then(alert); // exibe 2 depois de 1000ms ``` -JavaScript checks the object returned by `.then` handler in the line `(*)`: if it has a callable method named `then`, then it calls that method providing native functions `resolve`, `reject` as arguments (similar to executor) and waits until one of them is called. In the example above `resolve(2)` is called after 1 second `(**)`. Then the result is passed further down the chain. +JavaScript verifica o objeto retornado pelo tratador de `.then` na linha `(*)`: se ele possuir um método executável que possa ser chamado e possua nome `then`, então ele chama o método provendo funções nativas `resolve`, `reject` como argumentos (similar a um executor) e aguarda até que uma delas seja chamada. No exemplo acima, `resolve(2)` é chamada depois de 1 segundo `(**)`. Então o resultado é passado adiante pela cadeia. -This feature allows to integrate custom objects with promise chains without having to inherit from `Promise`. +Essa funcionalidade nos permite integrar objetos customizáveis com cadeias de promessas sem termos que herdar de `Promise`. ```` -## Bigger example: fetch +## Maior exemplo: fetch -In frontend programming promises are often used for network requests. So let's see an extended example of that. +Em programação frontend, promessas são utilizadas para requisições de rede com frequência. Então vamos ver um exemplo estendido disso. -We'll use the [fetch](mdn:api/WindowOrWorkerGlobalScope/fetch) method to load the information about the user from the remote server. The method is quite complex, it has many optional parameters, but the basic usage is quite simple: +Vamos usar o método [fetch](info:fetch) para carregar de um servidor remoto informações sobre o usuário. Ele possui vários parâmetros opcionais abordados em [separate chapters](info:fetch), mas a sintaxe básica é bem simples: ```js let promise = fetch(url); ``` -This makes a network request to the `url` and returns a promise. The promise resolves with a `response` object when the remote server responds with headers, but *before the full response is downloaded*. +Isso faz uma requisição de rede para a `url` e retorna uma promessa. A promessa é resolvida com um objeto `response` quando o servidor remoto responder com os cabeçalhos, mas *antes do download completo da resposta*. -To read the full response, we should call a method `response.text()`: it returns a promise that resolves when the full text downloaded from the remote server, with that text as a result. +Para ler a resposta completa, devemos chamar o método `response.text()`: isso retorna uma promessa que é resolvida quando o texto completo é baixado do servidor remoto, com esse texto como resultado. -The code below makes a request to `user.json` and loads its text from the server: +O código abaixo faz uma requisição a `user.json` e carrega seu texto do servidor: ```js run fetch('/article/promise-chaining/user.json') - // .then below runs when the remote server responds + // .then abaixo executa quando o servidor remoto responder .then(function(response) { - // response.text() returns a new promise that resolves with the full response text - // when we finish downloading it + // response.text() retorna uma nova promessa que é resolvida com o texto completo da resposta + // quando ela é baixada por completo return response.text(); }) .then(function(text) { - // ...and here's the content of the remote file + // ...e aqui está o conteúdo do arquivo remoto alert(text); // {"name": "iliakan", isAdmin: true} }); ``` -There is also a method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it. +O objeto `response` retornado pelo `fetch` também inclui o método `response.json()` que lê os dados remotos e faz o parser deles como JSON. No nosso caso, isso é ainda mais conveniente, então vamos trocar para isso. -We'll also use arrow functions for brevity: +Também vamos utilizar arrow functions para brevidade: ```js run -// same as above, but response.json() parses the remote content as JSON +// mesmo que acima, mas response.json() faz o parser do conteúdo remoto como JSON fetch('/article/promise-chaining/user.json') .then(response => response.json()) - .then(user => alert(user.name)); // iliakan + .then(user => alert(user.name)); // iliakan, obtém o nome do usuário ``` -Now let's do something with the loaded user. +Agora, vamos fazer algo com o usuário carregado. -For instance, we can make one more request to github, load the user profile and show the avatar: +Por exemplo, podemos fazer mais uma requisição ao GitHub, carregar o perfil do usuário e exibir o seu avatar. ```js run -// Make a request for user.json +// Fazer uma requisição para user.json fetch('/article/promise-chaining/user.json') - // Load it as json + // Carregar como json .then(response => response.json()) - // Make a request to github + // Fazer uma requisição ao GitHub .then(user => fetch(`https://api.github.com/users/${user.name}`)) - // Load the response as json + // Carregar a resposta como json .then(response => response.json()) - // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it) + // Exibir a imagem do avatar (githubUser.avatar_url) por 3 segundos (talvez animá-la) .then(githubUser => { let img = document.createElement('img'); img.src = githubUser.avatar_url; @@ -305,13 +287,13 @@ fetch('/article/promise-chaining/user.json') }); ``` -The code works, see comments about the details, but it should be quite self-descriptive. Although, there's a potential problem in it, a typical error of those who begin to use promises. +O código funciona; veja os comentários para os detalhes. Porém, há um problema em potencial nele, um erro comum para aqueles que começam a usar promessas. -Look at the line `(*)`: how can we do something *after* the avatar has finished showing and gets removed? For instance, we'd like to show a form for editing that user or something else. As of now, there's no way. +Observe a linha `(*)`: como podemos fazer algo *após* o avatar acabar de ser exibido e ser removido? Por exemplo, queremos exibir um formulário para edição do usuário ou outra coisa. Do jeito que está, não há como. -To make the chain extendable, we need to return a promise that resolves when the avatar finishes showing. +Para tornar a cadeia extensível, precisamos retornar uma promessa que seja resolvida quando o avatar acabar de ser exibido. -Like this: +Desta forma: ```js run fetch('/article/promise-chaining/user.json') @@ -319,7 +301,7 @@ fetch('/article/promise-chaining/user.json') .then(user => fetch(`https://api.github.com/users/${user.name}`)) .then(response => response.json()) *!* - .then(githubUser => new Promise(function(resolve, reject) { + .then(githubUser => new Promise(function(resolve, reject) { // (*) */!* let img = document.createElement('img'); img.src = githubUser.avatar_url; @@ -329,21 +311,19 @@ fetch('/article/promise-chaining/user.json') setTimeout(() => { img.remove(); *!* - resolve(githubUser); + resolve(githubUser); // (**) */!* }, 3000); })) - // triggers after 3 seconds - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + // disparado após 3 segundoss + .then(githubUser => alert(`Finalizou exibição de ${githubUser.name}`)); ``` -Now right after `setTimeout` runs `img.remove()`, it calls `resolve(githubUser)`, thus passing the control to the next `.then` in the chain and passing forward the user data. - -As a rule, an asynchronous action should always return a promise. +Isto é, o tratador do `.then` na linha `(*)` agora retorna `new Promise`, que se torna estabelecida apenas após a chamada de `resolve(githubUser)` em `setTimeout` `(**)`. O próximo `.then` na cadeia vai aguardar por isso. -That makes it possible to plan actions after it. Even if we don't plan to extend the chain now, we may need it later. +Como uma boa prática, uma ação assíncrona deve sempre retornar uma promessa. Isso torna possível planejar ações após ela; mesmo que não planejemos estender a cadeia agora, podemos precisar disso depois. -Finally, we can split the code into reusable functions: +Finalmente, podemos dividir o código em funções reusáveis: ```js run function loadJson(url) { @@ -370,18 +350,18 @@ function showAvatar(githubUser) { }); } -// Use them: +// Utilizando as funções: loadJson('/article/promise-chaining/user.json') .then(user => loadGithubUser(user.name)) .then(showAvatar) - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + .then(githubUser => alert(`Finalizou exibição ${githubUser.name}`)); // ... ``` -## Summary +## Resumo -If a `.then` (or `catch/finally`, doesn't matter) handler returns a promise, the rest of the chain waits until it settles. When it does, its result (or error) is passed further. +Se um tratador `.then` (ou `catch/finally`, não importa) retornar uma promessa, o resto da cadeia aguarda até ela ser estabelecida. Quando isso acontece, o resultado (ou erro) é passado adiante. -Here's a full picture: +Aqui está a ideia geral: ![](promise-handler-variants.svg) diff --git a/1-js/11-async/03-promise-chaining/getMessage.js b/1-js/11-async/03-promise-chaining/getMessage.js index 6c5893433..0cb2f216c 100644 --- a/1-js/11-async/03-promise-chaining/getMessage.js +++ b/1-js/11-async/03-promise-chaining/getMessage.js @@ -1,3 +1,3 @@ function getMessage() { - return "Hello, world!"; + return "Olá, mundo!"; } diff --git a/1-js/11-async/03-promise-chaining/head.html b/1-js/11-async/03-promise-chaining/head.html index 31c6b4271..f523e332e 100644 --- a/1-js/11-async/03-promise-chaining/head.html +++ b/1-js/11-async/03-promise-chaining/head.html @@ -5,30 +5,11 @@ script.src = src; script.onload = () => resolve(script); - script.onerror = () => reject(new Error("Script load error: " + src)); + script.onerror = () => reject(new Error("Erro ao carregar script: " + src)); document.head.append(script); }); } - -class HttpError extends Error { - constructor(response) { - super(`${response.status} for ${response.url}`); - this.name = 'HttpError'; - this.response = response; - } -} - -function loadJson(url) { - return fetch(url) - .then(response => { - if (response.status == 200) { - return response.json(); - } else { - throw new HttpError(response); - } - }) -} return valuereturn promisethrow errorstate: "fulfilled" result: valuestate: "rejected" result: error...with the result of the new promise...state: "pending" result: undefinedthe call of .then(handler) always returns a promise:if handler ends with…that promise settles with: \ No newline at end of file diff --git a/1-js/11-async/03-promise-chaining/promise-then-chain.svg b/1-js/11-async/03-promise-chaining/promise-then-chain.svg index d0faae2b7..0a3ea6d37 100644 --- a/1-js/11-async/03-promise-chaining/promise-then-chain.svg +++ b/1-js/11-async/03-promise-chaining/promise-then-chain.svg @@ -1,38 +1 @@ - - - - promise-then-chain.svg - Created with sketchtool. - - - - - .then - - - - new Promise - - - resolve(1) - - - return 2 - - - - - .then - - - return 4 - - - - - .then - - - - - \ No newline at end of file +.thennew Promiseresolve(1)return 2.thenreturn 4.then \ No newline at end of file diff --git a/1-js/11-async/03-promise-chaining/promise-then-many.svg b/1-js/11-async/03-promise-chaining/promise-then-many.svg index d745dee5e..ce8dc1c0c 100644 --- a/1-js/11-async/03-promise-chaining/promise-then-many.svg +++ b/1-js/11-async/03-promise-chaining/promise-then-many.svg @@ -1,32 +1 @@ - - - - promise-then-many.svg - Created with sketchtool. - - - - - .then - - - - new Promise - - - resolve(1) - - - - - .then - - - - - .then - - - - - \ No newline at end of file +.thennew Promiseresolve(1).then.then \ No newline at end of file