我近期在 SF 作了一場關於 Promise 的專題分享,作的很用心,內容也很豐富,基本能夠一站式解決全部關於 Promise 的問題。歡迎你們前來圍觀:javascript
Promise 的 N 種用法html
Promise 在處理異步的時候是個很好的選擇,能夠減小嵌套層次,讓代碼更好讀,邏輯更清晰。ES6 將其加入規範,jQuery 3.0 也修改實現向規範靠攏(3.0 發佈公告)。一些新增元素好比 .fetch()
原生就 「thenable
」,不過大多數以往的 API 還要依賴回調,這個時候,咱們只要將它們從新封裝,就能避開嵌套陷阱,享受 Promise 帶來的愉悅體驗。java
先來看下 Promise 的通常用法。jquery
// 聲明 Promise 對象 var p = new Promise(function (resolve, reject) { // 無論啥時候,該執行then了,就調用 resolve setTimeout(function () { resolve(1); }, 5000); // 或者無論啥問題,就調用 reject if (somethingWrong) { reject('2'); } }); // 使用 Promise 對象 p.then(function (num) { // 對應上面的 resolve console.log(num); // 1 }, function (num) { // 對應上面的 reject console.log(num); // 2 });
Promise 的驅動模型並不複雜:任何操做,假定它只有兩個結果,成功或者失敗。那麼只須要在合適的時間調用合適的程序,進入合適的後續步驟便可。.then()
顧名思義,就是下一步的意思,當前面的 Promise 有告終果——即調用 resolve
或者 reject
——以後,就啓動對應的處理函數。git
Promise 實例建立後就會開始執行,斷定結果須要咱們本身來,好比加載成功,或者知足某個條件,等等。經過串聯 .then()
則能夠完成一系列操做。每次調用 .then()
都會建立一個新的 Promise 實例,它會靜靜等待前面的實例狀態改變後再開始執行。es6
接下來開始封裝。思路很簡單,FileReader
除了提供各類 read 方法,還有幾個事件鉤子,其中 onerror
和 onload
很明顯能夠做爲判斷任務是否完成的依據。加載成功的話,就須要用到文件內容,因此將文件或文件內容傳遞到下一步也十分必要。github
最後完成的代碼以下:segmentfault
function reader (file, options) { options = options || {}; return new Promise(function (resolve, reject) { let reader = new FileReader(); reader.onload = function () { resolve(reader); }; reader.onerror = reject; if (options.accept && !new RegExp(options.accept).test(file.type)) { reject({ code: 1, msg: 'wrong file type' }); } if (!file.type || /^text\//i.test(file.type)) { reader.readAsText(file); } else { reader.readAsDataURL(file); } }); }
爲了能真正派上用場,裏面還有一些驗證文件類型的操做,不過跟本文主旨無關,略過不表。這段代碼的核心是建立一個 Promise 對象,等待 FileReader 讀取完成後調用 resolve
方法,或者出現問題時調用 reject
方法。promise
Github Gist 裏也放了一份。babel
接下來就能夠在項目中使用了:
reader(file) .then(function (reader) { console.log(reader.result); }) .catch(function (error) { console.log(error); });
.then()
支持兩個參數,第一個在 Promise 成功時啓動,第二個天然在失敗時啓動。用 .catch()
能夠實現一樣地效果。Promise 的好處除了可讀性更佳之外,返回的 Promise 對象還能夠任意傳遞,繼續進行鏈式調用,有很大想象空間。
.then()
因而咱們不妨串聯更多操做(原本想寫個斷點續傳的,回頭再說吧):
reader(file) .then(function (reader) { return new Promise(function (resolve, reject) { // 就隨便暫停個5秒吧…… setTimeout(function () { resolve(reader.result); }, 5000); }); }) .then(function (content) { console.log(content); });
這實際上是我第一次用 Promise,上次翻譯 jQuery 發佈公告的時候我它也只是只知其一;不知其二,對它的解讀也糊里糊塗。我很喜歡在業餘項目中學習使用新技術,最近開發 Chrome 插件的時候就嘗試了一把,感受不錯。使用過程比我想象的複雜也比我想象的簡單,這套設計很棒,能解決很多實際問題,也給了我很大啓發,未來我應該會把不少地方的實現都作這樣的修改。
除去第一段的各個連接,還有一些文章值得一看。