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