From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../javascript/guide/usando_promises/index.html | 269 +++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 files/pt-br/web/javascript/guide/usando_promises/index.html (limited to 'files/pt-br/web/javascript/guide/usando_promises/index.html') diff --git a/files/pt-br/web/javascript/guide/usando_promises/index.html b/files/pt-br/web/javascript/guide/usando_promises/index.html new file mode 100644 index 0000000000..a0dd09c8c2 --- /dev/null +++ b/files/pt-br/web/javascript/guide/usando_promises/index.html @@ -0,0 +1,269 @@ +--- +title: Usando promises +slug: Web/JavaScript/Guide/Usando_promises +tags: + - Guía + - Intermediário + - JavaScript + - Promise + - Promises +translation_of: Web/JavaScript/Guide/Using_promises +--- +
{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +

Uma {{jsxref("Promise")}} é um objeto que representa a eventual conclusão ou falha de uma operação assincrona. Como a maioria das pessoas consomem promisses já criadas, este guia explicará o consumo de promisses devolvidas antes de explicar como criá-las.

+ +

Essencialmente, uma promise é um objeto retornado para o qual você adiciona callbacks, em vez de passar callbacks para uma função.

+ +

Por exemplo, em vez de uma função old-style que espera dois callbacks, e chama um deles em uma eventual conclusão ou falha:

+ +
function successCallback(result) {
+  console.log("It succeeded with " + result);
+}
+
+function failureCallback(error) {
+  console.log("It failed with " + error);
+}
+
+doSomething(successCallback, failureCallback);
+ +

…funções modernas retornam uma promisse e então você pode adicionar seus callbacks:

+ +
const promise = doSomething();
+promise.then(successCallback, failureCallback);
+ +

…ou simplesmente:

+ +
doSomething().then(successCallback, failureCallback);
+ +

Nós chamamos isso de chamada de função assincrona. Essa convenção tem várias vantagens. Vamos explorar cada uma delas.

+ +

Garantias

+ +

Ao contrário dos callbacks com retornos de funções old-style, uma promisse vem com algumas garantias:

+ + + +

Mas o benefício mais imediato da promises é o encadeamento.

+ + + +

Encadeamento

+ +

Uma necessidade comum é executar duas ou mais operações assincronas consecutivas, onde cada operação subsequente começa quando a operação anterior é bem sucedida, com o resultado do passo anterior. Nós conseguimos isso criando uma cadeia de promises.

+ +

Aqui está a magica: a função then retorna uma nova promise, diferente da original:

+ +
const promise = doSomething();
+const promise2 = promise.then(successCallback, failureCallback);
+
+ +

ou

+ +
const promise2 = doSomething().then(successCallback, failureCallback);
+
+ +

Essa segunda promise representa a conclusão não apenas de doSomething(), mas também do successCallback ou failureCallback que você passou, que podem ser outras funções assincronas que retornam uma promise. Quando esse for o caso, quaisquer callbacks adicionados a promise2 serão enfileiradas atrás da promise retornada por successCallback ou failureCallback.

+ +

Basicamente, cada promise representa a completude de outro passo assíncrono na cadeia.

+ +

Antigamente, realizar operações assíncronas comuns em uma linha levaria à clássica pirâmide da desgraça :

+ +
doSomething(function(result) {
+  doSomethingElse(result, function(newResult) {
+    doThirdThing(newResult, function(finalResult) {
+      console.log('Got the final result: ' + finalResult);
+    }, failureCallback);
+  }, failureCallback);
+}, failureCallback);
+
+ +

Ao invés disso, com funções modernas, nós atribuímos nossas callbacks às promises retornadas, formando uma cadeia de promise:

+ +
doSomething().then(function(result) {
+  return doSomethingElse(result);
+})
+.then(function(newResult) {
+  return doThirdThing(newResult);
+})
+.then(function(finalResult) {
+  console.log('Got the final result: ' + finalResult);
+})
+.catch(failureCallback);
+
+ +

Os argumentos para then são opcionais, e catch(failureCallback) é uma abreviação para then(null, failureCallback). Você pode também pode ver isso escrito com arrow functions:

+ +
doSomething()
+.then(result => doSomethingElse(result))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => {
+  console.log(`Got the final result: ${finalResult}`);
+})
+.catch(failureCallback);
+
+ +

Importante: Sempre retorne um resultado, de outra forma as callbacks não vão capturar o resultado da promise anterior.

+ +

Encadeando depois de um catch

+ +

É possivel encadear depois de uma falha, i.e um catch, isso é muito útil para realizar novas ações mesmo depois de uma falha no encadeamento. Leia o seguinte exemplo: 

+ +
new Promise((resolve, reject) => {
+    console.log('Initial');
+
+    resolve();
+})
+.then(() => {
+    throw new Error('Something failed');
+
+    console.log('Do this');
+})
+.catch(() => {
+    console.log('Do that');
+})
+.then(() => {
+    console.log('Do this whatever happened before');
+});
+
+ +

Isso vai produzir o seguinte texto:

+ +
Initial
+Do that
+Do this whatever happened before
+
+ +

Observe que o texto "Do this" não foi impresso por conta que o erro "Something failed" causou uma rejeição.

+ +

Propagação de erros

+ +

Na pirâmide da desgraça vista anteriormente, você pode se lembrar de ter visto failureCallback três vezes, em comparação a uma única vez no fim da corrente de promessas:

+ +
doSomething()
+.then(result => doSomethingElse(result))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => console.log(`Got the final result: ${finalResult}`))
+.catch(failureCallback);
+
+ +

Basicamente, uma corrente de promessas para se houver uma exceção, procurando por catch handlers no lugar. Essa modelagem de código segue bastante a maneira de como o código síncrono funciona:

+ +
try {
+  const result = syncDoSomething();
+  const newResult = syncDoSomethingElse(result);
+  const finalResult = syncDoThirdThing(newResult);
+  console.log(`Got the final result: ${finalResult}`);
+} catch(error) {
+  failureCallback(error);
+}
+
+ +

Essa simetria com código assíncrono resulta no syntactic sugar async/await presente no ECMAScript 2017:

+ +
async function foo() {
+  try {
+    const result = await doSomething();
+    const newResult = await doSomethingElse(result);
+    const finalResult = await doThirdThing(newResult);
+    console.log(`Got the final result: ${finalResult}`);
+  } catch(error) {
+    failureCallback(error);
+  }
+}
+
+ +

É construído sobre promesas, por exemplo, doSomething() é a mesma função que antes. Leia mais sobre a sintaxe aqui.

+ +

Por pegar todos os erros, até mesmo exceções jogadas(thrown exceptions) e erros de programação, as promises acabam por solucionar uma falha fundamental presente na pirâmide da desgraça dos callbacks. Essa característica é essencial para a composição funcional das operações assíncronas.

+ +

Criando uma Promise em torno de uma callback API antiga

+ +

Uma {{jsxref("Promise")}} pode ser criada do zero utilizando o seu construtor. Isto deve ser necessário apenas para o envolvimento de APIs antigas.

+ +

Em um mundo ideal, todas as funções assincronas já retornariam promises. Infelizmente, algumas APIs ainda esperam que os retornos de suceso e/ou falha sejam passados da maneira antiga. O exemplo por excelência é o {{domxref("WindowTimers.setTimeout", "setTimeout()")}} function:

+ +
setTimeout(() => saySomething("10 seconds passed"), 10000);
+
+ +

Misturar chamadas de retorno e promeses de old-style é problemático. Se saySomething falhar ou contiver um erro de programação, nada o captura.

+ +

Por sorte nós podemos envolve-la em uma promise. É uma boa prática envolver funções problemáticas no menor nivel possível, e nunca chama-las diretamente de novo:

+ +
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
+
+ +

Basically, the promise constructor takes an executor function that lets us resolve or reject a promise manually. Since setTimeout doesn't really fail, we left out reject in this case.

+ +

Basicamente, um construtor de promises pega uma função executora que nos deixa resolver ou rejeitar uma promise manualmente. Desde que setTimeout não venha a falhar, nos deixamos a rejeição de fora nesse caso

+ +

Composição

+ +

{{jsxref("Promise.resolve()")}} e {{jsxref("Promise.reject()")}} são atalhos para se criar manualmente uma promessa que já foi resolvida ou rejeitada, respectivamente. Isso pode ser útil em algumas situações.

+ +

{{jsxref("Promise.all()")}} e {{jsxref("Promise.race()")}} são duas ferramentas de composição para se executar operações assíncronas em paralelo.

+ +

Uma composição sequencial é possível usando JavaScript de uma forma esperta:

+ +
[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());
+
+ +

Basicamente reduzimos um vetor de funções assíncronas a uma cadeia de promessas equivalentes a: Promise.resolve().then(func1).then(func2);

+ +

Isso também pode ser feito com uma função de composição reutilizável, que é comum em programação funcional:

+ +
const applyAsync = (acc,val) => acc.then(val);
+const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
+ + + +

A função composeAsync aceitará qualquer número de funções como argumentos e retornará uma nova função que aceita um valor incial a ser passado pelo pipeline de composição. Isso é benéfico porque alguma, ou todas as funções, podem ser assíncronas ou síncronas, e é garantido de que serão executadas na ordem correta.

+ +
const transformData = composeAsync(func1, asyncFunc1, asyncFunc2, func2);
+transformData(data);
+
+ +

No ECMAScript 2017, uma composição sequencial pode ser feita sde forma mais simples com async/await:

+ +
for (const f of [func1, func2]) {
+  await f();
+}
+
+ +

Cronometragem

+ +

Para evitar surpresas, funções passadas para then nunca serão chamadas sincronamente, mesmo com uma função ja resolvida:

+ +
Promise.resolve().then(() => console.log(2));
+console.log(1); // 1, 2
+
+ +

Instead of running immediately, the passed-in function is put on a microtask queue, which means it runs later when the queue is emptied at the end of the current run of the JavaScript event loop, i.e. pretty soon:

+ +

Ao invés de rodar imediatamente, a função passada é colocada em uma micro tarefa, o que significa que ela roda depois que a fila estiver vazia no final do atual processo de evento de loop do Javascript, isto é muito em breve

+ +
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+wait().then(() => console.log(4));
+Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
+console.log(1); // 1, 2, 3, 4
+
+ +

Ver também

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}

-- cgit v1.2.3-54-g00ecf