摘要:是一個對象,它的內部其實有三種狀態。已拒絕的異步操作未成功結束。方法則是將對象的狀態改變為失敗,同時將錯誤的信息傳遞到后續錯誤處理的操作。在第二個中拿到數據并且捕獲。使用的寫法比一般的寫法更加清晰明確。
## 前言
今天來分享下promise的用法,es6偉大發明之一,當初我學習的時候也是蠻頭大的,不知道為啥,整個腦子就是,我在哪,我要干啥的懵圈,后面認真學習之后,覺得真是十分好用,下面就來一起學習下吧。
為什么會有promise首先為什么會有promise的存在,其實很多人都知道的,其中最大的問題就是在處理多個有依賴關系的異步操作時,會出現回調地獄( callback hell ),如下:
$.ajax({ url:?"....", success:?function?(data)?{ $.ajax({ url:?"....", success:?function?(data)?{ } }); } });
promise提供了一個優雅的方式,來解決這個問題,同時提供了很多的錯誤捕獲機制。
如何使用promise我們先不講promise的理論語法,這樣會一開始就降低學習的欲望,直接來看使用案例,然后去理解。
new Promise(function (resolve, reject) { // 假設此處是異步請求某個數據 $.ajax({ url:?"......", success:?function?(res)?{ if (res.code === 200) { resolve(res.data); } else { reject("獲取data失敗"); } } }) }) .then(function A(data) { // 成功,下一步 console.log( data); }, function B(error) { // 失敗,做相應處理 console.log(error) }); console: sucess error
解析:
首先我們在promise函數里,執行我們的異步操作得到data
如果成功的話,通過resolve函數數據傳遞出來,如果失敗。通過reject把錯誤信息傳遞出來
然后在.then里可以接受傳遞出來的數據,.then()里面接受兩個函數,第一個函數接收resolve傳遞出來的值,也就是正確情況下的處理,第二個函數接收reject傳遞的信息,也就是錯誤的情況下的處理。
初始狀態( pending )。
已完成( fulfilled ): Promise 的異步操作已結束成功。
已拒絕( rejected ): Promise 的異步操作未成功結束。
resolve 方法可以使 Promise 對象的狀態改變成成功,同時傳遞一個參數用于后續成功后的操作。
reject 方法則是將 Promise 對象的狀態改變為失敗,同時將錯誤的信息傳遞到后續錯誤處理的操作。
---(onFulfilled, onRejected)
鏈式then當然,我們既然解決回調地獄,一個異步,看不出來啥優勢,現在看多個異步請求, 為了代碼簡約,我們用setTimeout來代替ajax請求 作為異步操作,如下:
new Promise((resolve, reject) => { setTimeout( () => { if (...){ resolve([1, 2, 3]) } else { reject("error"); } }, 2000); }) .then( data => { console.log(value); // 打印出[1, 2, 3] return new Promise( (resolve, reject)=> { // 新的異步請求,需要promise對象 let data2 = 1 + data; setTimeout( () => { if (...) { resolve(data2); } else { reject("error2") } }, 2000); }); }, error => { cosnole.log(error) }) .then( data2 => { console.log(data2 ); }, error => { cosnole.log(error) });
-這個例子中,第一個異步操作得到數據[1, 2, 3],傳遞到第一個then中,我們在第一個then中運用拿到的數據,進行第二次異步操作,并把結果傳遞出去。在第二個then中拿到數據,并且捕獲error。
可以看到本來嵌套的兩個異步操作,現在清晰多了,而且鏈式接無數個then
then里面的可捕獲錯誤的函數,可以捕獲到上面的所有then的錯誤,所以只在最后一個then里,寫錯誤捕獲函數就可以。
每次異步操作時候需要返回一個新的promise,因為只有用promise對象才會等異步操作執行完,才去執行下面的then,才能拿到異步執行后的數據,所以第二個then里的異步請求,也需要聲明Promise對象。如果then里面返回常量,可以直接返回。如下:
new Promise((resolve, reject) => { setTimeout( () => { if (...){ resolve([1, 2, 3]) } else { reject("error"); } }, 2000); }) .then( value => { return "222"; // 如果是直接返回常量,可直接return }) .then( value2 => { console.log(value2 ); // 打印出222 })
下面忽略error情況,看兩個例子,大家可以自己思考下打印結果
new Promise(resolve => { setTimeout( () => { resolve("value1"); }, 2000); }) .then( value1 => { console.log(value1); (function () { return new Promise(resolve => { setTimeout(() => { console.log("Mr.Laurence"); resolve("Merry Xmas"); }, 2000); }); }()); return false; }) .then( value => { console.log(value + " world"); }); value1 false world Mr.Laurence
new Promise( resolve => { console.log("Step 1"); setTimeout(() => { resolve(100); }, 1000); }) .then( value => { return new Promise(resolve => { console.log("Step 1-1"); setTimeout(() => { resolve(110); }, 1000); }) .then( value => { console.log("Step 1-2"); return value; }) .then( value => { console.log("Step 1-3"); return value; }); }) .then(value => { console.log(value); console.log("Step 2"); }); console: Step 1 Step 1-1 Step 1-2 Step 1-3 110 Step 2catch
catch 方法是 then(onFulfilled, onRejected) 方法當中 onRejected 函數的一個簡單的寫法,也就是說可以寫成 then(fn).catch(fn),相當于 then(fn).then(null, fn)。使用 catch 的寫法比一般的寫法更加清晰明確。我們在捕獲錯誤的時候,直接在最后寫catch函數即可。
let promise = new Promise(function(resolve, reject) { throw new Error("Explosion!"); }); promise.catch(function(error) { console.log(error.message); // "Explosion!" });
上面代碼等于與下面的代碼
let promise = new Promise(function(resolve, reject) { throw new Error("Explosion!"); }); promise.catch(function(error) { console.log(error.message); // "Explosion!" });
new Promise( resolve => { setTimeout( () => { throw new Error("bye"); }, 2000); }) .then( value => { }) .catch( error => { console.log( "catch", error); }); 控制臺會直接報錯 Uncaught Error: bye
解析:因為異步情況下,catch已經執行完了,錯誤才拋出,所以無法捕獲,所以要用reject,如下:
new Promise( (resolve, reject) => { setTimeout( () => { reject("bye"); }, 2000); }) .then( value => { console.log( value + " world"); }) .catch( error => { console.log( "catch", error); }); catch bye 利用reject可以抓捕到promise里throw的錯
new Promise( resolve => { setTimeout( () => { resolve(); }, 2000); }) .then( value => { throw new Error("bye"); }) .then( value => { throw new Error("bye2"); }) .catch( error => { console.log( "catch", error); }); console: Error: bye
new Promise( resolve => { setTimeout( () => { resolve(); }, 2000); }) .then( value => { throw new Error("bye"); }) .catch( error => { console.log( "catch", error); }) .then( value => { throw new Error("bye2"); }) .catch( error => { console.log( "catch", error); }); console: Error: bye console: Error: bye2 catch 抓捕到的是第一個沒有被捕獲的錯誤
new Promise(resolve => { setTimeout(() => { resolve(); }, 1000); }) .then( () => { throw new Error("test1 error"); }) .catch( err => { console.log("I catch:", err); // 此處捕獲了 "test1 error",當錯誤被捕獲后,下面代碼可以繼續執行 }) .then( () => { console.log(" here"); }) .then( () => { console.log("and here"); throw new Error("test2 error"); }) .catch( err => { console.log("No, I catch:", err); // 此處捕獲了 "test2 error" }); I catch: Error: test2 error here and here I catch: Error: test2 error
new Promise(resolve => { setTimeout(() => { resolve(); }, 1000); }) .then( () => { throw new Error("test1 error"); }) .catch( err => { console.log("I catch:", err); // 此處捕獲了 "test1 error",不影響下面的代碼執行 throw new Error("another error"); // 在catch里面丟出錯誤,會直接跳到下一個能被捕獲的地方。 }) .then( () => { console.log("and here"); throw new Error("test2 error"); }) .catch( err => { console.log("No, I catch:", err); // 此處捕獲了 "test2 error" }); I catch: Error: test2 error I catch: Error: another error
new Promise(resolve => { setTimeout(() => { resolve(); }, 1000); }) .then( () => { console.log("start"); throw new Error("test1 error"); }) .then( () => { console.log("arrive here"); }) .then( () => { console.log("... and here"); throw new Error("test2 error"); }) .catch( err => { console.log("No, I catch:", err); // 捕獲到了第一個 }); No, I catch: Error: test1 error at Promise.then (Promise.all:8:1
Promise.all([1, 2, 3]) .then( all => { console.log("1:", all); }) [1, 2, 3]
Promise.all([function () {console.log("ooxx");}, "xxoo", false]) .then( all => { console.log( all); }); ?[?, "xxoo", false]
let p1 = new Promise( resolve => { setTimeout(() => { resolve("I"m P1"); }, 1500); }); let p2 = new Promise( (resolve, reject) => { setTimeout(() => { resolve("I"m P2"); }, 1000); }); let p3 = new Promise( (resolve, reject) => { setTimeout(() => { resolve("I"m P3"); }, 3000); }); Promise.all([p1, p2, p3]).then( all => { console.log("all", all); }).catch( err => { console.log("Catch:", err); }); all (3)?["I"m P1", "I"m P2", "I"m P3"]
案例:刪除所有數據后,做一些事情、、、、 db.allDocs({include_docs: true}).then(function (result) { return Promise.all(result.rows.map(function (row) { return db.remove(row.doc); })); }).then(function (arrayOfResults) { // All docs have really been removed() now! });Promise.resolve
Promise.resolve() .then( () => { console.log("Step 1"); })其他
Promise.resolve("foo").then(Promise.resolve("bar")).then(function (result) { console.log(result); }); VM95:2 foo 如果你向 then() 傳遞的并非是一個函數(比如 promise) 它實際上會將其解釋為 then(null),這就會導致前一個 promise 的結果會穿透下面How do I gain access to resultA here?
function getExample() { return promiseA(…).then(function(resultA) { // Some processing return promiseB(…); }).then(function(resultB) { // More processing return // How do I gain access to resultA here? }); }解決 Break the chain
function getExample() { var a = promiseA(…); var b = a.then(function(resultA) { // some processing return promiseB(…); }); return Promise.all([a, b]).then(function([resultA, resultB]) { // more processing return // something using both resultA and resultB }); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/102205.html
摘要:的幾個擴展總結描述和相反,當所有的被拒絕之后,方法執行完成的決議,如果存在一個執行完成的決議,方法則執行拒絕里邊的所有實例反過來就好了執行到此執行到此描述忽略被拒絕的,只需要有一個完成的,方法就執行完成操作,如果全部的都被拒絕,方法執行拒絕 Promise的幾個擴展API總結 1. Promise.none 描述: 和 Promise.all 相反,當所有的promise被拒絕之后,n...
摘要:對于的來說基元函數包括組合函數的類型簽名返回情況完成如果傳入的可迭代對象為空,會同步地返回一個已完成狀態的。相反,如果是在指定的時間之后完成,剛返回結果就是一個拒絕狀態的從而觸發方法指定的回調函數。在行中,對每個小任務得到的結果進行匯總。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 從ES6 開始,我們大都使用的是 P...
摘要:構造函數的實現我們在使用的時候其實是使用關鍵字創建了一個的實例,其實是一個類,即構造函數,下面來實現構造函數。 showImg(https://segmentfault.com/img/remote/1460000018998456); 閱讀原文 概述 Promise 是 js 異步編程的一種解決方案,避免了 回調地獄 給編程帶來的麻煩,在 ES6 中成為了標準,這篇文章重點不是敘...
摘要:使用對象的好處在于可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。對象異步操作拋出錯誤,狀態就會變為,就會調用方法指定的回調函數處理這個錯誤。 Promise 含義 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了 Promise 對象。 所謂 P...
摘要:以上代碼,可以完美通過所有用例。在的函數中,為何需要這個同樣是因為規范中明確表示因此我們需要這樣的來確保只會執行一次。其他情況,直接返回以該值為成功狀態的對象。 Promise是前端面試中的高頻問題,我作為面試官的時候,問Promise的概率超過90%,據我所知,大多數公司,都會問一些關于Promise的問題。如果你能根據PromiseA+的規范,寫出符合規范的源碼,那么我想,對于面試...
閱讀 1195·2021-09-22 15:24
閱讀 2295·2019-08-30 15:44
閱讀 2623·2019-08-30 10:55
閱讀 3362·2019-08-29 13:25
閱讀 1644·2019-08-29 13:09
閱讀 1401·2019-08-26 14:05
閱讀 1395·2019-08-26 13:58
閱讀 1988·2019-08-26 11:57