GraphQL的思想是經過將多個一般不相關的請求批處理到一個網絡調用中來減小網絡往返的次數。經過一次傳送許多信息,大大減小了等待時間。當多個順序的網絡往返能夠用一個來代替時,它特別有用。好吧,老實說,每一個網絡瀏覽器都會自動爲咱們完成此操做。例如,當咱們打開一個包含多個圖像的網站時,瀏覽器將同時發送每一個圖像的HTTP請求。或者,確切地說,它將開始不超過與同一主機的必定數量的鏈接。介於2到8之間,具體取決於瀏覽器。一樣適用於多個AJAX / RESTful調用(請參閱fetch()
API),默認狀況下是併發的,開發人員方面無需進行任何額外的工做。實際上,這就是_A_在AJAX 1中的含義。html
若是Web瀏覽器已經能夠同時對多個數據發出併發請求,爲何還要麻煩GraphQL?有一些優勢:java
默認狀況下,在Java的GraphQL服務器實現中, 最後一句_不正確_。記住,咱們爲每一個非平凡的屬性和關係提供了不少解析器。提醒一下,這是咱們的解析器的外觀:react
@Component class PlayerResolver implements GraphQLResolver<Player> { Billing billing(Player player) //... String name(Player player) //... int points(Player player) //... ImmutableList<Item> inventory(Player player) //... }
這些方法中的每個僅在須要時才被調用,而且每一個都是潛在的重量級。不幸的是,默認狀況下,服務器端的GraphQL引擎會順序調用解析器方法。所以,與RESTful API(!)相比,整體延遲要差得多。Restful API將利用瀏覽器的內置併發性。爲了顯示這種行爲的糟糕程度,我設置了Zipkin並跟蹤了每一個解析器: git
請注意,徹底不相關的解析程序彼此之間是如何等待的。幸運的是,此性能瓶頸很容易解決。原來GraphQL引擎瞭解CompletableFuture
!github
看看通過改進的解析器API:api
@Component class PlayerResolver implements GraphQLResolver<Player> { CompletableFuture<Billing> billing(Player player) //... CompletableFuture<String> name(Player player) //... CompletableFuture<Integer> points(Player player) //... CompletableFuture<List<Item>> inventory(Player player) //... }
併發的來源在這裏並不重要。有可能:瀏覽器
HttpClient
,Mono
使用Mono.toFuture()
,Deferred
使用Kotlin的[ ]對象進行轉換asCompletableFuture()
關鍵是,GraphQL考慮了這一將來,並同時調用多個解析器。看看Zipkin的效果如何: 服務器
此圖像教給咱們兩件事:網絡
inventory
解析器對總延遲的影響最大?也許,做爲客戶,您能夠跳過該屬性並將等待時間減小一半?GraphQL爲客戶提供了絕佳的機會來以細粒度的方式自定義其查詢。您要決定要多少數據。API生產者再也不負責。一樣,API沒必要是最低公分母。每一個客戶都作出獨立的決定,而不是_一個合適的選擇_。最後但並不是最不重要的一點是,可以輕鬆地描述每一個解析器是一個巨大的勝利。GitHub上提供了本系列全部文章
的完整源代碼,包括Docker上的Zipkin設置。併發