五月22,2019 javascript
做者:Senthil Padmanabhan和Pranav Jha前端
從發佈之日起,WebAssembly 就在前端世界引發了巨大轟動。Web 社區欣然接受了接受用 JavaScript 之外的其餘編程語言爲瀏覽器編寫的並運行代碼的想法。首先,WebAssembly 始終保證本機速度比 JavaScript 快得多。在咱們的 eBay 上也同樣。java
咱們的工程師對此想法感到很是興奮,並一直關注着規格及其發展。一旦將WebAssembly 1.0 運用於全部主流瀏覽器後,eBay周圍的團隊就渴望嘗試一下。git
有一個問題:雖然有不少用例從 WebAssembly 中受益,但在電子商務中的技術範圍仍然很顯得很原始。咱們找不到合適的用例來利用 WebAssembly。提出了一些建議,可是 JavaScript 自己就更好。在 eBay 上,當咱們評估新技術時,咱們要問的第一個問題是「這爲咱們的客戶增長了哪些潛在價值?」 除非對此有明確的瞭解,不然咱們不會繼續進行下一步。很容易被新的閃亮事物帶偏,經常忘記這一事實可能對咱們的客戶沒有任何影響,而只會使現有的工做流程變得複雜。用戶體驗始終賽過開發人員體驗。可是 WebAssembly 是不一樣的。它具備巨大的潛力,咱們只是沒有合適的用例。好吧,最近發生了變化。github
iOS 和 Android 上的 eBay 本地應用程序在銷售流程中均具備條形碼掃描功能。用設備攝像頭掃描產品 UPC 條形碼並自動填寫表單,從而消除了人工開銷。這是僅本機應用程序的功能。須要在設備上進行一些密集的圖像處理才能從相機流中檢測條形碼編號。而後將檢索到的代碼發送到後端服務,完成表單填寫。這意味着設備上的圖像處理流程必須具備很高的性能。對於本機應用程序,咱們將內部構建的 C++ 掃描程序庫編譯爲適用於 iOS 和 Android 的本機代碼。從相機流識別出產品條形碼的性能很是好。咱們正在逐步過渡到 iOS 和 Android 本機 API,可是 C++ 庫仍然是最可靠的。web
條形碼掃描對咱們的賣家來講是一種直觀的功能,由於它使表單流程更加流暢。不幸的是,咱們的 Web 移動端用戶未啓用此功能。除了沒有條形碼掃描,咱們已經爲 Web 移動端提供了優化的銷售流程,而賣方必須手動輸入產品UPC,從而增長了使用的阻力。docker
以前,咱們已經研究過爲移動網絡實施條形碼掃描功能。實際上,咱們使用開源 JavaScript 庫BarcodeReader推出了條形碼掃描功能。這是兩年前的事了。問題在於它僅在20%的時間內表現良好。其他80%的時間很是慢,用戶認爲它已損壞。超時是常態。這也不出所料,由於 JavaScript 確實能夠和本機代碼同樣快,可是僅當它處於「熱路徑」時,即由JIT進行了優化的編譯。根源在於,JavaScript 引擎使用大量啓發式方法來肯定代碼路徑是否「熱」,而且不能保證每一個實例都獲得優化。這種不一致顯然令用戶很無奈,所以咱們不得不由用了該功能。可是如今狀況有了新變化。隨着 Web 平臺的快速發展,這個問題從新浮出水面:「咱們可否爲 Web 實施性能一致的條形碼掃描功能?」npm
一種選擇是等待Shape Detection API。提出的 Web API 爲 Web 帶來了許多本機圖像檢測功能,其中之一是條形碼檢測。但還處於起步階段,要實現跨瀏覽器兼容性還有很長的路要走。即便這樣,也不能保證在每一個平臺上都能正常使用。所以,咱們必須考慮其餘選項。編程
這恰是 WebAssembly 發揮期所長地方。若是在 WebAssembly 中實現了條形碼掃描功能,咱們能夠保證其性能始終如一。WebAssembly 字節碼的強類型和不變結構,使編譯器始終停留在熱路徑上。最重要的是,咱們有一個現有的 C++ 庫正在爲本機應用程序完成這項工做。C++ 庫是編譯成WebAssembly 的理想選擇。咱們認爲咱們面前有一條光明的大道。...好吧,也許還不徹底是。後端
咱們實現基於 WebAssembly 的條形碼掃描的項目設計很是簡單。
.wasm
文件。.wasm
文件。
WebAssembly工做流程
彙編
任何 WebAssembly 項目的第一步都是擁有定義明確的編譯管道。Emscripten 已成爲事實上的用於編譯 WebAssembly 的工具鏈,可是關鍵是要有一個一致的環境來產生肯定性的輸出。咱們的前端基於 Node.js,這意味着咱們須要一個與 npm 工做流程一塊兒使用的解決方案。幸運的是,大約在同一時間,Surma Das發表了「 Emscripten and npm 」一文。基於Docker的 WebAssembly 編譯方法很是合理,由於它消除了大量的開銷。在文章中建議,咱們用由trzeci提供的 Emscripten 的Docker鏡像。咱們必須對自定義 C++ 庫進行一些調整,以使其兼容於WebAssembly。所謂調整就主要是反覆試驗。最終,咱們可以進行編譯,而且可以在咱們現有的構建管道中創建簡潔的 WebAssembly 工做流。
很快,可是…
咱們計算掃描功能的性能的方法是經過分析 wasm API 每秒能夠處理的幀數。即 wasm API 接收一幀來自實時攝像機流的圖像快照像素數據,執行計算並返回響應。連續進行此操做,直到檢測到條形碼爲止。咱們以衆所周知的【每秒幀數】(FPS)度量標準對其進行度量。
在咱們的測試中,WebAssembly 實現平均以驚人的 50 FPS 執行。可是,在當時的超時閾值下,僅有60%的狀況能正確識別。即便具備如此高的 FPS,它也沒法快速檢測出剩餘40%有效掃描的條形碼,最終只能無奈顯示警告消息。爲了進行比較,咱們以前嘗試的 JavaScript 實施大多數狀況下僅以1 FPS 執行。所以,能夠確定的是,WebAssembly 速度更快(50倍),但因爲某種緣由,它沒法在分配的時間內檢測到近一半的條形碼。還應該提到的是,在某些狀況下,JavaScript 表現很是出色,而且可以當即檢測到條形碼。一種明顯的選擇是延遲顯示警告消息,但這隻會增長用戶的沮喪感,並且咱們實際上並無解決真正的問題。因此咱們放棄了這個主意。
最初,咱們不知道爲何對於本機應用程序運行良好的自定義 C++ 庫沒法在 Web 上產生相同的結果。通過大量的測試和調試,咱們發現聚焦對象的角度以及背景陰影決定了成功檢測的時間。那它如何在本機應用程序中工做?好吧,在本機應用程序中,咱們使用內置的 API 來自動聚焦或將用戶的點擊聚焦提供給被掃描對象的中心。這使本機應用程序能夠始終將高質量的圖像像素數據(即僅有關條形碼的信息)發送到掃描庫。這避免了圖像模糊的狀況。所以,始終如一的快速響應時間。
既而咱們對這件事情有了一個認識,咱們認爲也許其餘的本地庫在不一樣的聚焦條件下可能會表現更好。開源條形碼閱讀器ZBar很是受歡迎且穩定。更重要的是,它適用於模糊和顆粒狀圖像。爲何不試試呢?因爲咱們已經創建了 WebAssembly 工做流程,所以能夠無縫編譯和部署 ZBar,由於WebAssembly 是無縫的。而後,咱們開始評估 ZBar 實現。性能不錯,大約 15 FPS(不如咱們的自定義 C++ 庫)。可是,對於相同的超時閾值,成功率接近80%。絕對是對咱們自已的 C++ 庫的改進,但仍不是100%可靠。
咱們仍然對結果不滿意,可是咱們發現了一些意想不到的事情。在 ZBar 超時的狀況下,自定義 C++ 庫可以很是快地完成工做。這真是一個驚喜。顯然,基於圖像快照的質量,這兩個庫的執行狀況有所不一樣。這帶給了咱們一個新辦法。
用多線程再搶救一下
您可能猜對了。爲何不建立兩個 Web Worker 線程-一個用於 ZBar,一個用於自定義 C++ 庫-並使它們相互競爭。中獎響應(即第一個發送有效條形碼的響應)被髮送到主線程,而且全部工做線程都被終止。咱們進行了設置,並開始進行內部測試,以模擬儘量多的狀況。當掃描有效的條形碼時,此設置爲咱們提供了95%的成功率。比咱們之前的成功率要好得多,但仍不到100%。
一個奇怪的建議是也將原始的 JavaScipt 庫加入了組合。這將使其成爲三個線程。老實說,咱們認爲這不會有所收穫。可是,因爲咱們對工做人員界面進行了標準化,所以很容易嘗試。令咱們驚訝的是,三個線程相互競爭,成功率確實接近 100%。這又是徹底出乎意料的。正如文章前面提到的那樣,JavaScript 在某些狀況下確實表現良好,而且這個因素彷佛能夠彌補上面的差距。所以,是的,「始終押在 JavaScript 上。」 開個玩笑,下圖很好地概述了咱們實現的最終體系結構。
基於Web的條形碼掃描儀架構
下圖顯示了高級流程圖:
條形碼掃描儀流程圖
關於資源文件加載的說明
呈現主頁後,將預取條形碼掃描功能所需的資源。這是爲了確保快速加載賣家着陸頁,並準備進行交互。在頁面的加載事件以後,使用XMLHttpRequest預取並緩存 WebAssembly 資源文件(wasm文件和關聯的粘合代碼腳本)和 JavaScript 掃描功能庫 。這裏要注意的一點是它們沒有執行。這是爲了使主線程保持空閒以進行用戶交互。僅當用戶點擊條形碼圖標時纔會執行。若是用戶在加載資源文件以前點擊條形碼圖標,咱們將按需加載並當即執行。條形碼事件處理程序和工做線程控制程序捆綁在一塊兒做爲初始頁面加載的一部分,可是它們的尺寸很小。
通過全面測試和內部測試後,該功能做爲 A/B 測試啓動。實驗中的「測試方」輸入區顯示了條形碼掃描儀圖標(下面的屏幕截圖),而「控制方」沒有顯示。
最終產品
用來評估 A/B 測試成功與否的度量標準稱爲「草稿完成率」。這是列表從草稿階段到成功完成並提交的比例。草案完工率是一個很好的指標,能夠支持如下觀點:減小使用阻力並證實經過條形碼掃描儀的無縫銷售流應該可以完成更多清單。咱們將測試運行了幾個星期,當結果返回時,確實很是使人滿意。它與咱們最初的假設徹底一致。啓用條形碼掃描器後,表單流程的草稿完成率提升了30%。
A/B 測試結果
咱們還添加了埋點,以獲取有關哪一種類型的掃描功能獲勝的信息。結果符合預期,ZBar 佔成功掃描的 53%,其次是自定義 C++庫,佔34%,最後是JavaScript 庫,佔13%。
WebAssembly 的整個旅程對咱們來講是一次很棒的學習經歷。工程師對新技術感到很是興奮,並當即想嘗試一下。若是相同的技術對以客戶爲中心的指標產生積極的影響,那將是雙重榮幸。這暗示了本文的早期觀點。技術發展很是迅速。天天咱們都會聽到新事物的發佈。可是隻有少數幾個對客戶有所幫助,WebAssembly 就是其中之一。這是咱們今後練習中學到的最大經驗- 「對99件事情說【不】,對客戶真正重要的一件事情說【是】。」
下一步,咱們正在考慮將條形碼掃描功能擴展到移動端的買家,這將使買家能夠掃描物品進行搜索和購買。咱們還將研究經過 Shape Detection API 和其餘瀏覽器內置攝像頭功能來加強此功能。同時,咱們很高興在eBay 上找到了 WebAssembly 的正確用例,並將該技術引入電子商務。
特別感謝Surma Das和Lin Clark在 WebAssembly 上發表的許多文章。它確實幫助咱們在各類狀況下暢通無阻。