當我們撰寫 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,名稱依語言不同而不同) 來管理這成串的地獄:
Futurefuture = 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-objectJQuery 的 API 功能完整,用起來最為簡潔,因為 method 的 parameter 的 type 很鬆。
Akka
再來是 Akka 內附的 Future API (Both Scala/Java)
http://doc.akka.io/docs/akka/2.0.1/scala/futures.htmlAkka 的 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