ES6 - Promessas
Promise Syntax
A sintaxe relacionada à promessa é mencionada abaixo, onde, p é o objeto da promessa, resolve é a função que deve ser chamada quando a promessa é executada com sucesso e reject é a função que deve ser chamada quando a promessa encontra um erro.
let p = new Promise(function(resolve,reject){
let workDone = true; // some time consuming work
if(workDone){
//invoke resolve function passed
resolve('success promise completed')
}
else{
reject('ERROR , work could not be completed')
}
})
Exemplo
O exemplo abaixo mostra uma função add_positivenos_async()que adiciona dois números de forma assíncrona. A promessa é resolvida se valores positivos forem passados. A promessa é rejeitada se valores negativos forem passados.
<script>
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
add_positivenos_async(10, 20)
.then(successHandler) // if promise resolved
.catch(errorHandler);// if promise rejected
add_positivenos_async(-10, -20)
.then(successHandler) // if promise resolved
.catch(errorHandler);// if promise rejected
function errorHandler(err) {
console.log('Handling error', err)
}
function successHandler(result) {
console.log('Handling success', result)
}
console.log('end')
</script>
A saída do código acima será conforme mencionado abaixo -
end
Handling success 30
Handling error NOT_Postive_Number_Passed
Encadeamento de promessas
Promises chaining pode ser usado quando temos uma sequência de asynchronous taskspara ser feito um após o outro. As promessas são acorrentadas quando uma promessa depende do resultado de outra promessa. Isso é mostrado no exemplo abaixo
Exemplo
No exemplo abaixo, add_positivenos_async() functionadiciona dois números de forma assíncrona e rejeita se valores negativos forem passados. O resultado da chamada de função assíncrona atual é passado como parâmetro para as chamadas de função subsequentes. Observe cadathen() método tem uma instrução de retorno.
<script>
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
add_positivenos_async(10,20)
.then(function(result){
console.log("first result",result)
return add_positivenos_async(result,result)
}).then(function(result){
console.log("second result",result)
return add_positivenos_async(result,result)
}).then(function(result){
console.log("third result",result)
})
console.log('end')
</script>
A saída do código acima será conforme indicado abaixo -
end
first result 30
second result 60
third result 120
Alguns métodos comuns usados do objeto de promessa são discutidos abaixo em detalhes -
promessa.all ()
Esse método pode ser útil para agregar os resultados de várias promessas.
Sintaxe
A sintaxe para o promise.all() método é mencionado abaixo, onde, iterableé um objeto iterável. Por exemplo, Array.
Promise.all(iterable);
Exemplo
O exemplo a seguir executa uma série de operações assíncronas [add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)]. Quando todas as operações são concluídas, a promessa está totalmente resolvida.
<script>
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
//Promise.all(iterable)
Promise.all([add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)])
.then(function(resolveValue){
console.log(resolveValue[0])
console.log(resolveValue[1])
console.log(resolveValue[2])
console.log('all add operations done')
})
.catch(function(err){
console.log('Error',err)
})
console.log('end')
</script>
A saída do código acima será a seguinte -
end
30
70
110
all add operations done
promessa.race ()
Essa função recebe uma série de promessas e retorna a primeira que foi acertada.
Sintaxe
A sintaxe para o promise.race()A função é mencionada abaixo, onde iterable é um objeto iterável. Por exemplo, Array.
Promise.race(iterable)
Exemplo
O exemplo a seguir usa uma matriz [add_positivenos_async(10,20),add_positivenos_async(30,40)] de operações assíncronas.
A promessa é resolvida sempre que qualquer uma das operações de adição for concluída. A promessa não esperará que outras operações assíncronas sejam concluídas.
<script>
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
} else
reject('NOT_Postive_Number_Passed')
})
return p;
}
//Promise.race(iterable)
Promise.race([add_positivenos_async(10,20),add_positivenos_async(30,40)])
.then(function(resolveValue){
console.log('one of them is done')
console.log(resolveValue)
}).catch(function(err){
console.log("Error",err)
})
console.log('end')
</script>
A saída do código acima será a seguinte -
end
one of them is done
30
Promisessão uma maneira limpa de implementar programação assíncrona em JavaScript (novo recurso do ES6). Antes das promessas, os retornos de chamada eram usados para implementar a programação assíncrona. Vamos começar entendendo o que é programação assíncrona e sua implementação, usando Callbacks.
Compreendendo o retorno de chamada
Uma função pode ser passada como parâmetro para outra função. Este mecanismo é denominado como umCallback. Um retorno de chamada seria útil em eventos.
O exemplo a seguir nos ajudará a entender melhor esse conceito.
<script>
function notifyAll(fnSms, fnEmail) {
console.log('starting notification process');
fnSms();
fnEmail();
}
notifyAll(function() {
console.log("Sms send ..");
},
function() {
console.log("email send ..");
});
console.log("End of script");
//executes last or blocked by other methods
</script>
No notifyAll()método mostrado acima, a notificação acontece através do envio de SMS e do envio de um e-mail. Portanto, o invocador do método notificationAll deve passar duas funções como parâmetros. Cada função assume uma única responsabilidade, como enviar SMS e enviar um e-mail.
A seguinte saída é exibida na execução bem-sucedida do código acima.
starting notification process
Sms send ..
Email send ..
End of script
No código mencionado acima, as chamadas de função são síncronas. Isso significa que o thread de interface do usuário estaria esperando para concluir todo o processo de notificação. As chamadas síncronas tornam-se chamadas de bloqueio. Vamos entender as chamadas sem bloqueio ou assíncronas agora.
Compreendendo AsyncCallback
Considere o exemplo acima.
Para habilitar o script, execute uma chamada assíncrona ou sem bloqueio para o método NoticeAll (). Devemos usar osetTimeout()método de JavaScript. Este método é assíncrono por padrão.
O método setTimeout () leva dois parâmetros -
Uma função de retorno de chamada.
O número de segundos após os quais o método será chamado.
Nesse caso, o processo de notificação foi encerrado com tempo limite. Portanto, levará um atraso de dois segundos, definido pelo código. O notificarAll () será invocado e a thread principal continua como se estivesse executando outros métodos. Portanto, o processo de notificação não bloqueará o thread principal de JavaScript.
<script>
function notifyAll(fnSms, fnEmail) {
setTimeout(function() {
console.log('starting notification process');
fnSms();
fnEmail();
}, 2000);
}
notifyAll(function() {
console.log("Sms send ..");
},
function() {
console.log("email send ..");
});
console.log("End of script"); //executes first or not blocked by others
</script>
A seguinte saída é exibida na execução bem-sucedida do código acima.
End of script
starting notification process
Sms send ..
Email send ..
No caso de vários retornos de chamada, o código parecerá assustador.
<script>
setTimeout(function() {
console.log("one");
setTimeout(function() {
console.log("two");
setTimeout(function() {
console.log("three");
}, 1000);
}, 1000);
}, 1000);
</script>
ES6 vem em seu socorro introduzindo o conceito de promessas. As promessas são "eventos de continuação" e ajudam a executar as várias operações assíncronas em um estilo de código muito mais limpo.
Exemplo
Vamos entender isso com um exemplo. A seguir está a sintaxe para o mesmo.
var promise = new Promise(function(resolve , reject) {
// do a thing, possibly async , then..
if(/*everthing turned out fine */) resolve("stuff worked");
else
reject(Error("It broke"));
});
return promise;
// Give this to someone
O primeiro passo para implementar as promessas é criar um método que use a promessa. Digamos neste exemplo, ogetSum()método é assíncrono, ou seja, sua operação não deve bloquear a execução de outros métodos. Assim que esta operação for concluída, ela notificará mais tarde o chamador.
O exemplo a seguir (Etapa 1) declara um objeto Promise 'var promessa'. O Promise Constructor leva as funções primeiro para a conclusão com sucesso da obra e outra para o caso de ocorrer um erro.
A promessa retorna o resultado do cálculo usando o callback de resolução e passando o resultado, ou seja, n1 + n2
Step 1 - resolver (n1 + n2);
Se getSum () encontrar um erro ou uma condição inesperada, ele invocará o método de retorno de chamada de rejeição no Promise e passará as informações do erro ao chamador.
Step 2 - rejeitar (Erro ("Negativos não suportados"));
A implementação do método é fornecida no código a seguir (PASSO 1).
function getSum(n1, n2) {
varisAnyNegative = function() {
return n1 < 0 || n2 < 0;
}
var promise = new Promise(function(resolve, reject) {
if (isAnyNegative()) {
reject(Error("Negatives not supported"));
}
resolve(n1 + n2)
});
return promise;
}
A segunda etapa detalha a implementação do chamador (PASSO 2).
O chamador deve usar o método 'then', que usa dois métodos de retorno de chamada - primeiro para sucesso e segundo para falha. Cada método leva um parâmetro, conforme mostrado no código a seguir.
getSum(5, 6)
.then(function (result) {
console.log(result);
},
function (error) {
console.log(error);
});
A seguinte saída é exibida na execução bem-sucedida do código acima.
11
Como o tipo de retorno de getSum () é uma promessa, podemos realmente ter várias instruções 'then'. O primeiro 'then' terá uma instrução de retorno.
getSum(5, 6)
.then(function(result) {
console.log(result);
returngetSum(10, 20);
// this returns another promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
},
function(error) {
console.log(error);
});
A seguinte saída é exibida na execução bem-sucedida do código acima.
11
30
O exemplo a seguir emite três chamadas then () com o método getSum ().
<script>
function getSum(n1, n2) {
varisAnyNegative = function() {
return n1 < 0 || n2 < 0;
}
var promise = new Promise(function(resolve, reject) {
if (isAnyNegative()) {
reject(Error("Negatives not supported"));
}
resolve(n1 + n2);
});
return promise;
}
getSum(5, 6)
.then(function(result) {
console.log(result);
returngetSum(10, 20);
//this returns another Promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
returngetSum(30, 40);
//this returns another Promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
},
function(error) {
console.log(error);
});
console.log("End of script ");
</script>
A seguinte saída é exibida na execução bem-sucedida do código acima.
O programa exibe 'fim do script' primeiro e, em seguida, os resultados da chamada do método getSum (), um por um.
End of script
11
30
70
Isso mostra que getSum () é chamado em estilo assíncrono ou estilo sem bloqueio. Promise oferece uma maneira limpa e agradável de lidar com os Callbacks.