14 January 2013

當我們撰寫 async 程式時,最常用的就是 callback:

   openFileAsync("a.png", (file) { 
      print( file.length ); 
   });

但是一旦 API 設計成 callback,後來就會沒完沒了:

  
   openFileAsync("a.png", (file) { 
      readImageAsync(file, (image) { 
           rotateImageAsync(image, 90, (rotated) {
                saveImageAsync(rotated......
          }); 
      });
   });

對於這個問題,觀察近年來的發展,有一個共同的趨勢,就是額外產生一個 Future 物件 (或叫做 Promise,名稱依語言不同而不同) 來管理這成串的地獄:


   Future
   
     future = openFileAsync("a.png");
   future.then( (file) { 
      print( file.length ); 
   });


   

當 async task 變多時,可以變成:


   openFileAsync("a.png")
       .chain( readImageAsync )    //chain() 也是回傳 Future
       .chain( (image) => rotateImageAsync(image, 90) )
       .then( saveImageAsync );

多了一個 Future 物件後,整個 async chain 程式更為明暸,也更容易維護。而且更可以操作更進階的 cancel, error handling, map, filter 等等功能。我可以說 這種提供 Composability 的 Future 取代 callback 的趨勢已經確立了。下面收集了一些最近看到的 API 發展

JQuery

最有名最多人碰過的應該是 JQuery 的 Deferred ,從 1.5 版開始就有了:

http://api.jquery.com/category/deferred-object

JQuery 的 API 功能完整,用起來最為簡潔,因為 method 的 parameter 的 type 很鬆。

Akka

再來是 Akka 內附的 Future API (Both Scala/Java)

http://doc.akka.io/docs/akka/2.0.1/scala/futures.html

Akka 的 Future 是個 monad,所以 composability 很高。另外,Twitter 那裡也用 scala 開發了一堆 framework,裡面他們也另外造了一個 Future。

Java Jdk8

Java 最早有 concurrent.Future,但那是 old style (只能 pull,不能 push,也不能 compose) 不過 jdk8 Doug Lea 重新設計了一個 CompletableFuture

http://cs.oswego.edu/pipermail/concurrency-interest/2012-December/010423.html

這個就是全功能了,配合 lambda 應該可以寫的很簡潔。不過目前的 method 有點混亂,還需要一點時間成熟。

Google Guava

Google 的 Guava 替 concurrent.Future 補強,多了個 ListenableFuture,這 jdk6 就能用了,大部份功能都有,但因為沒有 lambda 所以語法很慘。

http://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained

Python 3

Python 3.2 把 java concurrent 整包移植過去了,當然也包含 Future,不過這個 future 只多了 add_done_callback method,沒有 composability

http://docs.python.org/dev/library/concurrent.futures.html

Dart

Dart 因為是 web,一大堆的 api 都是 async 的,所以從一開始就加了 Future,composability 還不錯,使用上也算簡潔。最近 Dart M3 正在大改 Future/Stream/Iterator/DomEvent 相關的 API,打算把這些 listener 全部整合成統一的概念。

http://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/sdk/lib/async

Objective C

Objective C 在 github 上有看到一些,不過不是很完整,也不大像現在的 Composable Future 的設計趨勢。Composable Future 這個潮流大概還沒吹到 Objective C 吧... Objective C 有 Block 語法可用,但也就停在這裡了。偏偏 iOS 開發上 async 的操作很多,最後我只好自己刻了一個陽春的 Future 來克服這個問題。

node.js

node.js 我沒什麼研究,有看到一個 async library

https://github.com/caolan/async

設計的不錯。它雖然沒有 Future 的物件,但是提供 callback function 很好的 composability

其他

其他語言我就沒什麼涉獵了,Ruby/C# 那裡應該也有類似的。

ps. 上面我用 Composable 這個字用的很兇,我是參考這篇文章的定義:

http://blog.softmemes.com/2012/06/18/the-way-of-the-future-futures-in-net-java-and-javascript


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>