摘要:是一個對象,它的內(nèi)部其實有三種狀態(tài)。已拒絕的異步操作未成功結束。方法則是將對象的狀態(tài)改變?yōu)槭。瑫r將錯誤的信息傳遞到后續(xù)錯誤處理的操作。在第二個中拿到數(shù)據(jù)并且捕獲。使用的寫法比一般的寫法更加清晰明確。
## 前言
今天來分享下promise的用法,es6偉大發(fā)明之一,當初我學習的時候也是蠻頭大的,不知道為啥,整個腦子就是,我在哪,我要干啥的懵圈,后面認真學習之后,覺得真是十分好用,下面就來一起學習下吧。
為什么會有promise首先為什么會有promise的存在,其實很多人都知道的,其中最大的問題就是在處理多個有依賴關系的異步操作時,會出現(xiàn)回調(diào)地獄( callback hell ),如下:
$.ajax({ url:?"....", success:?function?(data)?{ $.ajax({ url:?"....", success:?function?(data)?{ } }); } });
promise提供了一個優(yōu)雅的方式,來解決這個問題,同時提供了很多的錯誤捕獲機制。
如何使用promise我們先不講promise的理論語法,這樣會一開始就降低學習的欲望,直接來看使用案例,然后去理解。
new Promise(function (resolve, reject) { // 假設此處是異步請求某個數(shù)據(jù) $.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函數(shù)里,執(zhí)行我們的異步操作得到data
如果成功的話,通過resolve函數(shù)數(shù)據(jù)傳遞出來,如果失敗。通過reject把錯誤信息傳遞出來
然后在.then里可以接受傳遞出來的數(shù)據(jù),.then()里面接受兩個函數(shù),第一個函數(shù)接收resolve傳遞出來的值,也就是正確情況下的處理,第二個函數(shù)接收reject傳遞的信息,也就是錯誤的情況下的處理。
初始狀態(tài)( pending )。
已完成( fulfilled ): Promise 的異步操作已結束成功。
已拒絕( rejected ): Promise 的異步操作未成功結束。
resolve 方法可以使 Promise 對象的狀態(tài)改變成成功,同時傳遞一個參數(shù)用于后續(xù)成功后的操作。
reject 方法則是將 Promise 對象的狀態(tài)改變?yōu)槭。瑫r將錯誤的信息傳遞到后續(xù)錯誤處理的操作。
---(onFulfilled, onRejected)
鏈式then當然,我們既然解決回調(diào)地獄,一個異步,看不出來啥優(yōu)勢,現(xiàn)在看多個異步請求, 為了代碼簡約,我們用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) });
-這個例子中,第一個異步操作得到數(shù)據(jù)[1, 2, 3],傳遞到第一個then中,我們在第一個then中運用拿到的數(shù)據(jù),進行第二次異步操作,并把結果傳遞出去。在第二個then中拿到數(shù)據(jù),并且捕獲error。
可以看到本來嵌套的兩個異步操作,現(xiàn)在清晰多了,而且鏈式接無數(shù)個then
then里面的可捕獲錯誤的函數(shù),可以捕獲到上面的所有then的錯誤,所以只在最后一個then里,寫錯誤捕獲函數(shù)就可以。
每次異步操作時候需要返回一個新的promise,因為只有用promise對象才會等異步操作執(zhí)行完,才去執(zhí)行下面的then,才能拿到異步執(zhí)行后的數(shù)據(jù),所以第二個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 函數(shù)的一個簡單的寫法,也就是說可以寫成 then(fn).catch(fn),相當于 then(fn).then(null, fn)。使用 catch 的寫法比一般的寫法更加清晰明確。我們在捕獲錯誤的時候,直接在最后寫catch函數(shù)即可。
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已經(jīng)執(zhí)行完了,錯誤才拋出,所以無法捕獲,所以要用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",當錯誤被捕獲后,下面代碼可以繼續(xù)執(zhí)行 }) .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",不影響下面的代碼執(zhí)行 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"]
案例:刪除所有數(shù)據(jù)后,做一些事情、、、、 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() 傳遞的并非是一個函數(shù)(比如 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 }); }
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102205.html
摘要:的幾個擴展總結描述和相反,當所有的被拒絕之后,方法執(zhí)行完成的決議,如果存在一個執(zhí)行完成的決議,方法則執(zhí)行拒絕里邊的所有實例反過來就好了執(zhí)行到此執(zhí)行到此描述忽略被拒絕的,只需要有一個完成的,方法就執(zhí)行完成操作,如果全部的都被拒絕,方法執(zhí)行拒絕 Promise的幾個擴展API總結 1. Promise.none 描述: 和 Promise.all 相反,當所有的promise被拒絕之后,n...
摘要:對于的來說基元函數(shù)包括組合函數(shù)的類型簽名返回情況完成如果傳入的可迭代對象為空,會同步地返回一個已完成狀態(tài)的。相反,如果是在指定的時間之后完成,剛返回結果就是一個拒絕狀態(tài)的從而觸發(fā)方法指定的回調(diào)函數(shù)。在行中,對每個小任務得到的結果進行匯總。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 從ES6 開始,我們大都使用的是 P...
摘要:構造函數(shù)的實現(xiàn)我們在使用的時候其實是使用關鍵字創(chuàng)建了一個的實例,其實是一個類,即構造函數(shù),下面來實現(xiàn)構造函數(shù)。 showImg(https://segmentfault.com/img/remote/1460000018998456); 閱讀原文 概述 Promise 是 js 異步編程的一種解決方案,避免了 回調(diào)地獄 給編程帶來的麻煩,在 ES6 中成為了標準,這篇文章重點不是敘...
摘要:使用是極好的,它是如此有用以至于我覺得應該好好研究一下,甚至是實現(xiàn)一個簡易的版本。構造函數(shù)檢查參數(shù)例如是不是函數(shù)啊初始化,創(chuàng)建對象執(zhí)行因此構造函數(shù)里面?zhèn)魅氲氖橇⒓幢粓?zhí)行的。 使用Promise是極好的,它是如此有用以至于我覺得應該好好研究一下Promise,甚至是實現(xiàn)一個簡易的版本。實現(xiàn)之前,我們先來看看Promise的用途: 使用Promise callback hell Promi...
摘要:使用對象的好處在于可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)。對象異步操作拋出錯誤,狀態(tài)就會變?yōu)椋蜁{(diào)用方法指定的回調(diào)函數(shù)處理這個錯誤。 Promise 含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。它由社區(qū)最早提出和實現(xiàn),ES6 將其寫進了語言標準,統(tǒng)一了用法,原生提供了 Promise 對象。 所謂 P...
摘要:以上代碼,可以完美通過所有用例。在的函數(shù)中,為何需要這個同樣是因為規(guī)范中明確表示因此我們需要這樣的來確保只會執(zhí)行一次。其他情況,直接返回以該值為成功狀態(tài)的對象。 Promise是前端面試中的高頻問題,我作為面試官的時候,問Promise的概率超過90%,據(jù)我所知,大多數(shù)公司,都會問一些關于Promise的問題。如果你能根據(jù)PromiseA+的規(guī)范,寫出符合規(guī)范的源碼,那么我想,對于面試...
閱讀 1181·2021-09-22 15:24
閱讀 2285·2019-08-30 15:44
閱讀 2615·2019-08-30 10:55
閱讀 3355·2019-08-29 13:25
閱讀 1639·2019-08-29 13:09
閱讀 1391·2019-08-26 14:05
閱讀 1379·2019-08-26 13:58
閱讀 1985·2019-08-26 11:57