Futures and Promises
Total Page:16
File Type:pdf, Size:1020Kb
Futures and promises May 7, 2014 Overview Overview ■ Futures in Clojure Clojure Javascript/JQuery Scala/Akka futures 2 / 15 Overview Clojure Future Future (example) Future (mechanics) Promises Javascript/JQuery Scala/Akka futures Clojure 3 / 15 Future Overview ■ Future: evaluates a body of code in another thread Clojure Future (def long-calculation Future (example) (future (apply + (range 1e8)))) Future (mechanics) Promises ◆ returns immediately Javascript/JQuery Scala/Akka ■ futures dereference @long-calculation ◆ blocks if value is not available yet ◆ returns saved value on subsequent calls ■ dereference with timeout (deref (future (Thread/sleep 5000) :done!) 1000 :impatient!) ;= :impatient! 4 / 15 Future (example) ( defn get−document [id] ; ... do some work to retrieve the identified ; document’s metadata ... {:url "http://www. mozilla .org/about/manifesto.en.html" : title "The␣Mozilla␣Manifesto" :mime "text/html" :content ( future (slurp "http://www. mozilla .org/about/manifesto.en.html"))}) ■ slurp fetches the document from the web ■ content is retreived once, starting immediately ◆ several threads requesting it wait for the same value ■ delay instead of future: starts only at first request 5 / 15 Future (mechanics) Overview ■ executed in the thread from the agents’ unlimited thread Clojure Future pool Future (example) Future ◆ may use IO (mechanics) Promises ■ Thread vs future Javascript/JQuery Scala/Akka ◆ futures cheaper than using thread directly ◆ more concise ◆ implements java.util.concurrent.Future 6 / 15 Promises Overview ■ delays and futures are bound to the result of a code Clojure Future block Future (example) ■ promise is not bound to any code block Future (mechanics) (def p (promise)) Promises Javascript/JQuery (realized? p) ;= false Scala/Akka futures (deliver p 42) ;= #<core$promise$reify__1707@3f0ba812: 42> (realized? p) ;= true @p ;= 42 ■ deliver assigns value to the promise ■ deref blocks until assigned, supports timeout too ■ similar to a one-time, single-value pipe ◆ sometimes called dataflow variables and are the building blocks of declarative concurrency (Oz) 7 / 15 Overview Clojure Javascript/JQuery Introduction Future event as object Making promises Deferred vs promise Pipes Pipe cascading Javascript/JQuery Scala/Akka futures 8 / 15 Introduction Overview ■ JQuery 1.4 and earlier Clojure Javascript/JQuery Introduction $.get(’/mydata’, { Future event as object success: onSuccess, Making promises failure: onFailure, Deferred vs promise always: onAlways Pipes }); Pipe cascading Scala/Akka futures ■ With JQuery 1.5 ajax functions you know ($.ajax, $.get, and $.post) now return Promises var promise = $.get(’/mydata’); promise.done(onSuccess); promise.fail(onFailure); promise.always(onAlways); ■ why this is better? 9 / 15 Future event as object Overview ■ All actions do not have to be defined on creation Clojure Javascript/JQuery ◆ Promise can be passed around Introduction Future event as ◆ effects (triggering animations, inserting HTML, object Making promises locking/unlocking user input, and so on) added Deferred vs incrementally (stacked) promise Pipes ■ the order of handlers is preserved Pipe cascading Scala/Akka futures ■ Combine promises ◆ in parallel, e.g. wait for 2 events (animation completion and ajax request result) ◆ pipeline, specify subsequent reactions to the future async results ■ resulting promise is the result of the final task in the series 10 / 15 Making promises ■ Either always+done or always+fail will be called var promptDeferred = new $.Deferred(); promptDeferred.always(function(){ console.log(’A choice was made:’); }); promptDeferred.done(function(){ console.log(’Starting game...’); }); promptDeferred.fail(function(){ console.log(’No game today.’); }); ■ triggering manually with resolve or reject $(’#playGame’).focus().on(’keypress’, function(e) { var Y = 121, N = 110; if (e.keyCode === Y) { promptDeferred.resolve(); } else if (e.keyCode === N) { promptDeferred.reject(); } else { return false; // our Deferred remains pending }; }); 11 / 15 Deferred vs promise Overview ■ Promise in JQuery is read-only view of a deferred Clojure Javascript/JQuery var promise1 = promptDeferred.promise(); Introduction var promise2 = promptDeferred.promise(); Future event as object console.log(promise1 === promise2); // true Making promises Deferred vs ■ In fact promise method returns self for promises promise Pipes console.log(promise1 === promise1.promise()); Pipe cascading // true Scala/Akka futures ■ convenient for protecting the deferred from external writes 12 / 15 Pipes Overview ■ you can’t attach handlers to the second task until the Clojure first one is complete Javascript/JQuery Introduction var getPromise = $.get(’/query’); Future event as object getPromise.done(function(data) { Making promises var postPromise = $.post(’/search’, data); Deferred vs promise }); Pipes // Now we’d like to attach handlers to postPromise Pipe cascading // see the problem: it is in internal scope Scala/Akka futures ■ first promise result is handled by the code, that should return second promise var getPromise = $.get(’/query’); var postPromise = getPromise.pipe(function(data) return $.post(’/search’, data); }); Effectively, pipe is a window into the future! ◆ if return simple value then it is final promise result 13 / 15 Pipe cascading Overview ■ pipe doesn’t require you to provide every possible Clojure callback: Javascript/JQuery ■ Introduction you’ll usually just want to write Future event as object var p = originalPromise.pipe(successCallback); Making promises Deferred vs promise or the following: Pipes Pipe cascading var p = originalPromise.pipe(null, failCallback); Scala/Akka futures ■ cascading: a failure is propagated to the last promise automatically var step1 = $.post(’/step1’, data1); var step2 = step1.pipe(function() { return $.post(’/step2’, data2); }); var lastStep = step2.pipe(function() { return $.post(’/step3’, data3); }); 14 / 15 Overview Clojure Javascript/JQuery Scala/Akka futures Scala/Akka futures 15 / 15.