Qual é a diferença entre um futuro e uma promessa?
Future
e Promise
?Ambos agem como um substituto para resultados futuros, mas onde está a principal diferença?
9 answers
De acordo com esta discussão, Promise
has finally been called CompletableFuture
for inclusion in Java 8, and its javadoc explains:
Um Futuro que pode ser explicitamente completado (definindo o seu valor e estado), e pode ser usado como uma etapa de completação, suportando funções e acções dependentes que desencadeiam após a sua conclusão.
Também é dado um exemplo na lista:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Note que a API final é ligeiramente diferente mas permite execução assíncrona semelhante:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
Futuros e promessas são conceitos muito semelhantes, a diferença é que um futuro é um recipiente apenas para leitura para um resultado que ainda não existe, enquanto uma promessa pode ser escrita (normalmente apenas uma vez). O Java 8 CompletableFuture e o goiaba SettableFuture podem ser considerados como promessas, porque o seu valor pode ser definido ("concluído"), mas eles também implementam a interface futura, portanto não há diferença para o cliente.
O resultado do futuro será definido por "outra pessoa" - pelo resultado de uma computação assíncrona. Note Como a tarefa do futuro - um clássico future - must be initialized with a Callable or Runnable, there is no-argument constructor, and both Future and FutureTask are read-only from the outside (the set methods of FutureTask are protected). O valor será definido para o resultado da computação a partir do interior.
Por outro lado, o resultado de uma promessa pode ser definido por "você" (ou, de fato, por qualquer um) a qualquer hora porque tem um método de setter público. O futuro completo e o futuro estável podem ser criados sem qualquer tarefa, e seu valor pode ser definido a qualquer momento. Você envia uma promessa para o código do cliente, e cumpri-la mais tarde como desejar.Note que o futuro completo não é uma promessa "pura", pode ser inicializado com uma tarefa tal como a futura tarefa, e a sua característica mais útil é o encadeamento não relacionado dos passos de processamento.
Note também que uma promessa não tem que ser um subtipo do futuro e não tem que ser o mesmo objeto. Em Scala um objeto futuro é criado por um assíncrono computação ou por um objeto de Promessa diferente . Em C++ a situação é semelhante: o objeto prometido é usado pelo produtor e o objeto futuro pelo consumidor. A vantagem desta separação é que o cliente não pode definir o valor do futuro.
Ambos a mola e a EJB 3.1 têm uma classe Assíncresulta, que é semelhante às promessas Scala/C++. AsyncResult do implement Future but this is not the real future: assynchronous methods in Spring / EJB return a objeto futuro diferente, apenas de leitura através de alguma magia de fundo, e este segundo futuro "real" pode ser usado pelo cliente para acessar o resultado.
Estou ciente de que já há uma resposta aceite, mas gostaria de acrescentar a minha opinião:
TLDR: futuro e promessa são os dois lados de uma operação assíncrona: consumidor/ouvinte vs. produtor/executor.
Como um chamador de um método API assíncrono, você terá umFuture
como um manípulo para o resultado da computação. Você pode, por exemplo, chamar get()
sobre ele para esperar que o cálculo para completar e recuperar o resultado.
Agora pense em como este método API é realmente implementado: o executor deve retornar um Future
imediatamente. Eles são responsáveis por completar esse futuro assim que o cálculo é feito (que eles saberão porque ele está implementando a lógica de expedição ;-)). Eles vão usar um Promise
/CompletableFuture
para fazer exatamente isso: construir e retornar o CompletableFuture
imediatamente, e chamar complete(T result)
uma vez que a computação é feita.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
A saída disto é:
Thank you mom for $10
A promessa da mãe foi criada, mas esperou por um evento de "conclusão".
CompletableFuture<Integer> promise...
Criaste tal evento, aceitaste a promessa dela e anunciaste os teus planos para agradecer à tua mãe.
promise.thenAccept...
Neste momento, a mãe começou a abri-la. bolsa...mas muito lento...
E o pai interferiu muito mais depressa e cumpriu a promessa em vez da tua mãe.
promise.complete(10);
Reparaste num executor que escrevi explicitamente?
Curiosamente, se você usar um executor implícito padrão em vez disso (commonPool) e o pai não está em casa, mas apenas a mãe com sua "bolsa lenta", então sua promessa só vai completar, se o programa viver mais tempo do que a mãe precisa para obter dinheiro da Bolsa.
O executor por omissão age como um "daemon" e não espera que todas as promessas sejam cumpridas. Não encontrei uma boa descrição deste facto...
Não tenho a certeza se isto pode ser uma resposta, mas como vejo o que os outros disseram para alguém, pode parecer que você precisa de duas abstrações separadas para ambos os conceitos, de modo que um deles (Future
) é apenas uma visão apenas de leitura do outro (Promise
) ... mas, na verdade, isso não é necessário.
Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
O foco está na compostabilidade usando o método then
como:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
O que faz com que a computação assíncrona pareça síncrona:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
O que é muito fixe.
(Não tão legal quanto async-await mas async-await {[[28]} apenas remove o boilerplate ....then (function (result) {....[[28]} a partir dele).
E, na verdade, a sua abstração é muito boa como a construtora de promessas.
new Promise( function(resolve, reject) { /* do it */ } );
Permite-lhe fornecer dois callbacks que podem ser usados para completar o Promise
com sucesso ou com um erro. De modo que apenas o código que constrói o Promise
pode completá-lo e o código que recebe um objeto Promise
já construído tem a vista apenas para leitura.
Com herança o acima pode ser alcançado se resolver e rejeitar são métodos protegidos.
Para o código do cliente, a promessa é para observar ou anexar callback quando um resultado está disponível, enquanto o futuro é esperar pelo resultado e, em seguida, continuar. Teoricamente tudo o que é possível fazer com futuros o que pode ser feito com promessas, mas devido à diferença de estilo, a API resultante para promessas em diferentes idiomas torna mais fácil acordes.
Nenhum método set na interface futura, apenas o método get, por isso é apenas para leitura. Sobre o futuro completo, este artigo pode ser útil. Completo
In this example you can take a look at how Promises can be used in Java para criar sequências assíncronas de chamadas:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));
Future
e Promise
são objectos proxy para resultado desconhecido
Promise
completa a Future
-
Future
- leitura / consumo de resultado desconhecido -
Promise
- write / producer of unknown result.
//Future has a reference to Promise
Future -> Promise
Como um producer
Eu promise
algo e responsável por isso
Como um consumer
que recuperou um promise
espero ter um resultado em future
Quanto a Java CompletableFutures
é um {[[2]} porque você pode definir o resultado e também ele instrumentos Future