摘要:前言假如需要向后端發送一個請求,并對返回的數據進行操作,可能我們第一時間想到的是回調函數。如果值本身就是一個對象,則替代默認的對象作為返回值如果值為其他值,則將這個值作為返回的的函數的參數值。
前言
假如需要向后端發送一個請求,并對返回的數據進行操作,可能我們第一時間想到的是回調函數。但如果接著又需要執行第二個、第三個...第n個異步操作,那么回調函數就會一層層的嵌套,嚴重影響了代碼可讀性和可維護性。
Promise就是解決這個問題的方案,Promise主要做的事情是把回調函數的嵌套邏輯替換成了符合正常人思維習慣的線性邏輯,本文主要介紹Promise的基本用法、API、鏈式操作、異常處理以及利用promise對數組進行異步操作的方法。
一、雜說Promise是從DOM中的Futures引入javascript的,理由大概是出現了像NodeJs這樣獨立于瀏覽器之外的JavaScript運行環境。在Promise正式被實現之前,部分JS庫,像Q、when、WinJS、RSVP.js、jQuery都根據Promises/A+標準分別實現了略有差異的”類Promise“對象。如果你的項目中用到了這些庫,不用擔心,標準的Promise對象提供了將這些”類Promise“對象轉換為標準Promise對象的方法(后文會提到)。關于Promise的兼容性,參考Can I Use。
Promise有三種狀態:pending、resolved、rejected,狀態之間的轉換只能從pending到resolved或rejected,并且狀態一旦轉換就再也無法改變;
Promise的API:
Promise的構造器接受一個函數,這個函數接受兩個參數:resolved,rejected。
promise.then(onResolved, onRejected), 不做贅述;
promise.catch(onRejected), promise.then(undefined, onRejected)的語法糖。
Promise.resolve(argument),返回一個Promise對象,具體取決于它接受的參數類型。
參數為一個Promise對象,直接返回這個對象;
參數為一個“類promise”對象,將其轉化成真正的Promise對象并返回;
參數為其他值,返回一個以參數值作為其resolved函數參數的Promise對象;
Promise.reject(obj), 返回一個以參數值(Error的實例)作為其reject函數參數的Promise對象;
Promise.all(array), 參數值為Promise數組(也可以包含"類Promise"對象),對數組的每一項調用Promise.resolve(),全部成功則resolved并返回返回值的數組,否則返回第一個rejected的error對象;
Promise.race(array), 返回數組中最先resolved或者rejected的那個Promise對象的返回值或者error對象。
二、基本用法Promise是一個JavaScript對象,它執行在未來的某個時刻才知道結果的操作并返回得到的值或者失敗的信息。
// Promise is something like this. var promise = new Promise(function(resolved, rejected) { doSomethingAsync(); if (success) { resolved(); } else { rejected(); } }) //How to use a promise. First arg is resolved, second is rejected promise.then(function(res) { console.log(res); }, function(err) { alert(err); })三、鏈式調用
如果僅有一個Promise對象的話,情況較為簡單,即在Promise對象被定義時異步操作就開始執行,我們關心的并不是它什么時候執行完畢,而是要在它執行完或者返回錯誤后對結果進行處理。但當多個Promise要按照一定的順序執行時,事情就變得復雜起來了。
function fetchSomething() { return new Promise(function(resolved) { if (success) { resolved(res); } }); } fetchSomething().then(function(res) { console.log(res); return fetchSomething(); }).then(function(res) { console.log("duplicate res"); return "done"; }).then(function(tip) { console.log(tip); })
then函數始終返回一個promise對象,后續的then要等待返回的promise resolve后才能執行,這樣就實現了線性邏輯的鏈式調用。而返回的promise取決于then函數本身return的值。如果return值本身就是一個promise對象,則替代默認的promise對象作為返回值;如果return值為其他值,則將這個值作為返回的promise的resolve函數的參數值。
四、異常處理從上面的代碼可以看出,then函數接受兩個參數:resolved、rejected。上面沒寫rejected是因為rejected函數是可選的,當然也可以在then之后寫catch,.catch(rejected)本質上是.then(undefined, rejected)的語法糖。
這兩種方式是有區別的,.then(resolved, rejected)只能捕獲之前的promise的異常,而寫在其后的.catch(undefined, rejected)還可以捕獲其resolved函數產生的異常。另外只要Promise鏈中有一個promise對象拋出異常,其后所有的resolved都被跳過,直到這個異常被rejected或者catch處理。
當需要用數組的數據執行異步操作,因為數組的遍歷方法forEach、map等都是同步的,所以結果的順序就取決于異步操作完成的順序,如果對順序有要求,這樣就不盡人意。
// 假設fetchID返回一個Promise對象 names.forEach(function(name) { fetchID(name).then(function(id) { renderInfo(id); }) })
這個時候就需要利用then()來制定順序:
names.reduce(function(sequence, name) { return sequence.then(function() { return fetchID(name); }).then(function(id) { renderID(id); }) }, Promise.then())
因為此時先遍歷的name處理的結果將作為后面的sequence,構成了鏈式關系,就避免了下載速度決定順序的問題。但仍然可以優化:因為此時的ID是獲取一個,render一個的。如果能夠先獲取所有的ID再逐條渲染的話,性能會更好。
Promise.all(names.map(fetchID)) .then(function(IDs) { IDS.forEach(function(id) { renderID(id); //同步 }) })
參考文章:
JavaScript Promises: an Introduction (自備梯子)
Master the JavaScript Interview: What is a Promise? (自備梯子)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87313.html
摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。怎么處理每個引擎都有一個基本組件,稱為調用棧。也就是說,如果有其他函數等待執行,函數是不能離開調用棧的。每個異步函數在被送入調用棧之前必須通過回調隊列。例如方法是在中傳遞的回調函數。 ? 翻譯:瘋狂的技術宅 原文:www.valentinog.com/blog/engine… 從Call Stack,Global Me...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。單線程的我們說是單線程的,因為有一個調用棧處理我們的函數。也就是說,如果有其他函數等待執行,函數是不能離開調用棧的。每個異步函數在被送入調用棧之前必須通過回調隊列。 翻譯:瘋狂的技術宅原文:https://www.valentinog.com/bl... 本文首發微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術文章 sh...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:為這些回調函數分別命名并分離存放可以在形式上減少嵌套,使代碼清晰,但仍然不能解決問題。如果在一個結束成功或失敗,同前面的說明后,添加針對成功或失敗的回調,則回調函數會立即執行。 異步? 我在很多地方都看到過異步(Asynchronous)這個詞,但在我還不是很理解這個概念的時候,卻發現自己常常會被當做已經很清楚(* ̄? ̄)。 如果你也有類似的情況,沒關系,搜索一下這個詞,就可以得到大致...
摘要:的執行與狀態無關當得到狀態不論成功或失敗后就會執行,原文鏈接參考鏈接對象 同期異步系列文章推薦談一談javascript異步javascript異步中的回調javascript異步與promisejavascript異步之Promise.resolve()、Promise.reject()javascript異步之Promise then和catchjavascript異步之async...
閱讀 672·2021-11-15 11:37
閱讀 4127·2021-09-09 09:34
閱讀 3567·2019-08-30 15:52
閱讀 2608·2019-08-29 14:03
閱讀 2849·2019-08-26 13:36
閱讀 1592·2019-08-26 12:16
閱讀 1599·2019-08-26 11:45
閱讀 3490·2019-08-23 18:41