Encadeamento de promessas

Resumo : neste tutorial, você aprenderá sobre o padrão de encadeamento de promessas JavaScript que encadeia as promessas para executar operações assíncronas em sequência.

Introdução ao encadeamento de promessas JavaScript

Às vezes, você deseja executar duas ou mais operações assíncronas relacionadas, onde a próxima operação começa com o resultado da etapa anterior. Por exemplo:

Primeiro, crie uma nova promessa que resolva o número 10 após 3 segundos:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});Linguagem de código:  JavaScript  ( javascript )

Observe que a setTimeout()função simula uma operação assíncrona.

Em seguida, invoque o then()método da promessa:

p.then((result) => {
    console.log(result);
    return result * 2;
});Linguagem de código:  JavaScript  ( javascript )

O retorno de chamada passado para o then()método é executado assim que a promessa é resolvida. No callback, mostramos o resultado da promessa e retornamos um novo valor multiplicado por dois ( result*2).

Como o then()método retorna um new Promisecom um valor resolvido para um valor, você pode chamar o then()método no retorno Promiseassim:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result);
    return result * 2;
}).then((result) => {
    console.log(result);
    return result * 3;
});Linguagem de código:  JavaScript  ( javascript )

Saída:

10
20

Neste exemplo, o valor de retorno do primeiro then()método é passado para o segundo then()método. Você pode continuar chamando o then()método sucessivamente da seguinte maneira:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result); // 10
    return result * 2;
}).then((result) => {
    console.log(result); // 20
    return result * 3;
}).then((result) => {
    console.log(result); // 60
    return result * 4;
});
Linguagem de código:  JavaScript  ( javascript )

Saída:

10
20
60

A maneira como chamamos os then()métodos dessa forma costuma ser chamada de cadeia de promessas.

A imagem a seguir ilustra a cadeia de promessas:

Encadeamento de promessas JavaScript

Vários manipuladores para uma promessa

Quando você chama o then()método várias vezes em uma promessa, não é o encadeamento da promessa. Por exemplo:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result); // 10
    return result * 2;
})

p.then((result) => {
    console.log(result); // 10
    return result * 3;
})

p.then((result) => {
    console.log(result); // 10
    return result * 4;
});Linguagem de código:  JavaScript  ( javascript )

Saída:

10
10
10

Neste exemplo, temos vários manipuladores para uma promessa. Esses manipuladores não têm relacionamentos. Além disso, eles são executados de forma independente e não passam o resultado de um para outro como a cadeia de promessas acima.

A imagem a seguir ilustra uma promessa que possui vários manipuladores:

JavaScript Promise Chaining - vários manipuladores

Na prática, você raramente usará vários manipuladores para uma promessa.

Devolvendo uma promessa

Quando você retorna um valor no then()método, o then()método retorna um novo Promiseque resolve imediatamente o valor de retorno.

Além disso, você pode retornar uma nova promessa no then()método, assim:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result * 2);
        }, 3 * 1000);
    });
}).then((result) => {
    console.log(result);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result * 3);
        }, 3 * 1000);
    });
}).then(result => console.log(result));
Linguagem de código:  JavaScript  ( javascript )

Saída:

10
20
60

Este exemplo mostra 10, 20 e 60 a cada 3 segundos. Este padrão de código permite executar algumas tarefas em sequência.

O seguinte modificou o exemplo acima:

function generateNumber(num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num);
    }, 3 * 1000);
  });
}

generateNumber(10)
  .then((result) => {
    console.log(result);
    return generateNumber(result * 2);
  })
  .then((result) => {
    console.log(result);
    return generateNumber(result * 3);
  })
  .then((result) => console.log(result));
Linguagem de código:  JavaScript  ( javascript )

Sintaxe de encadeamento de promessa

Às vezes, você tem várias tarefas assíncronas que deseja executar em sequência. Além disso, é necessário passar o resultado da etapa anterior para a próxima. Nesse caso, você pode usar a seguinte sintaxe:

step1()
    .then(result => step2(result))
    .then(result => step3(result))
    ...
Linguagem de código:  JavaScript  ( javascript )

Se você precisar passar o resultado da tarefa anterior para a próxima sem passar o resultado, use esta sintaxe:

step1()
    .then(step2)
    .then(step3)
    ...
Linguagem de código:  CSS  ( css )

Suponha que você queira executar as seguintes operações assíncronas em sequência:

  • Primeiro, obtenha o usuário do banco de dados.
  • Segundo, obtenha os serviços do usuário selecionado.
  • Terceiro, calcule o custo do serviço a partir dos serviços do usuário.

As funções a seguir ilustram as três operações assíncronas:

function getUser(userId) {
    return new Promise((resolve, reject) => {
        console.log('Get the user from the database.');
        setTimeout(() => {
            resolve({
                userId: userId,
                username: 'admin'
            });
        }, 1000);
    })
}

function getServices(user) {
    return new Promise((resolve, reject) => {
        console.log(`Get the services of ${user.username} from the API.`);
        setTimeout(() => {
            resolve(['Email', 'VPN', 'CDN']);
        }, 3 * 1000);
    });
}

function getServiceCost(services) {
    return new Promise((resolve, reject) => {
        console.log(`Calculate the service cost of ${services}.`);
        setTimeout(() => {
            resolve(services.length * 100);
        }, 2 * 1000);
    });
}Linguagem de código:  JavaScript  ( javascript )

O seguinte usa as promessas para serializar as sequências:

getUser(100)
    .then(getServices)
    .then(getServiceCost)
    .then(console.log);Linguagem de código:  CSS  ( css )

Saída

Get the user from the database.
Get the services of admin from the API.
Calculate the service cost of Email,VPN,CDN.
300Linguagem de código:  JavaScript  ( javascript )

Observe que o ES2017 introduziu o async/await que ajuda você a escrever um código mais limpo do que usar a técnica de encadeamento de promessas.

Neste tutorial, você aprendeu sobre a cadeia de promessas que executa várias tarefas assíncronas em sequência.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *