ES6中Promise的使用方法實(shí)例總結(jié)
本文實(shí)例講述了ES6中Promise的使用方法。分享給大家供大家參考,具體如下:
在javascript中,代碼是單線程執(zhí)行的,對(duì)于一些比較耗時(shí)的IO操作,都是通過(guò)異步回調(diào)函數(shù)來(lái)實(shí)現(xiàn)的。
但是這樣會(huì)存在一個(gè)問(wèn)題,當(dāng)下一個(gè)的操作需要上一個(gè)操作的結(jié)果時(shí),我們只能把代碼嵌到上一個(gè)操作的回調(diào)函數(shù)里,這樣一層嵌一層,最終形成回調(diào)地獄。
$.get('/login.php', function (login) { $.get('/user.php', function (user) { $.get('/info.php', function (info) { //代碼就這樣一層嵌一層,不夠直觀,維護(hù)也麻煩 }); }); });
為了解決這種問(wèn)題,ES6中就提供了Promise方法來(lái)解決這種問(wèn)題。
Promise是一個(gè)構(gòu)造函數(shù),通過(guò)它,我們可以創(chuàng)建一個(gè)Promise實(shí)例對(duì)象。
let p = new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); });
Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)有兩個(gè)參數(shù),resolve和reject。
resolve函數(shù)是將Promise的狀態(tài)設(shè)置為fulfilled(完成),reject函數(shù)是將Promise的狀態(tài)設(shè)置為rejected(失敗)。
上述代碼,我們并沒(méi)有進(jìn)行任何調(diào)用,當(dāng)運(yùn)行時(shí),間隔1秒后輸出了'OK'。所以這里需要注意,我們通常使用Promise時(shí),需要在外層再包裹一層函數(shù)。
let p = function () { return new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); }); }; p();
上面的代碼p();返回的是一個(gè)Promise實(shí)例對(duì)象,Promise對(duì)象上有 then() , catch() , finally() 方法。
then方法有兩個(gè)參數(shù),onFulfilled和onRejected,都是函數(shù)。
onFulfilled用于接收resolve方法傳遞過(guò)來(lái)的數(shù)據(jù),onRejected用于接收reject方法傳遞過(guò)來(lái)的數(shù)據(jù)。
let p = function () { return new Promise(function (resolve, reject) { setTimeout(() => { if (Math.random() > 0.5) { resolve('OK'); } else { reject('ERR'); } }, 1000); }); }; p().then(function (data) { console.log('fulfilled', data); }, function (err) { console.log('rejected', err); });
then()方法總是會(huì)返回一個(gè)Promise實(shí)例,這樣我們就可以一直調(diào)用then()。
在then方法中,你既可以return 一個(gè)具體的值 ,還可以return 一個(gè)Promise對(duì)象。
如果直接return的是一個(gè)數(shù)據(jù),那then方法會(huì)返回一個(gè)新Promise對(duì)象,并以該數(shù)據(jù)進(jìn)行resolve。
let p = function () { return new Promise(function (resolve, reject) { resolve(1); }); }; p().then(function (data) { console.log(`第 ${data} 次調(diào)用`); //注意這里直接返回的值 //then會(huì)創(chuàng)建一個(gè)新的Promise對(duì)象,并且以返回的值進(jìn)行resolve //那么該值會(huì)被下面的then方法的onFulfilled回調(diào)拿到 return ++data; }).then(function (data) { console.log(`第 ${data} 次調(diào)用`); return ++data; }).then(function (data) { console.log(`第 ${data} 次調(diào)用`); return ++data; });
如果返回的是一個(gè)Promise對(duì)象,請(qǐng)看下面代碼。
let p = function () { return new Promise(function (resolve, reject) { resolve(1); }); }; p().then(function (data) { console.log(`第 ${data} 次調(diào)用`); return new Promise(function (resolve, reject) { resolve(++data); }); }).then(function (data) { console.log(`第 ${data} 次調(diào)用`); return new Promise(function (resolve, reject) { resolve(++data); }); }).then(function (data) { console.log(`第 ${data} 次調(diào)用`); return new Promise(function (resolve, reject) { resolve(++data); }); });
其實(shí)效果與直接返回值的是一樣的。
即然then()可以進(jìn)行鏈?zhǔn)讲僮?,那我們最早之前的回調(diào)地獄寫(xiě)法,就可以通過(guò)它進(jìn)行改進(jìn)了。
function login() { return new Promise(function (resolve, reject) { $.get('/login.php', function (result) { resolve(result); }); }); } function user(data) { return new Promise(function (resolve, reject) { $.get('/user.php', function (result) { resolve(result); }); }); } function info(data) { return new Promise(function (resolve, reject) { $.get('/info.php', function (result) { resolve(result); }); }); } login().then(function (data) { console.log('處理login'); //把login異步處理獲取的數(shù)據(jù),傳入到下一個(gè)處理中。 return user(data); }).then(function (data) { console.log('處理user'); //把user異步處理獲取的數(shù)據(jù),傳入到下一個(gè)處理中。 return info(data); }).then(function (data) { console.log('處理info'); });
這樣修改后,回調(diào)地獄層層嵌套的結(jié)構(gòu)就變的清晰多了。上述代碼是偽代碼。
Promise對(duì)象還有一個(gè)catch方法,用于捕獲錯(cuò)誤,該方法與 then(null, onRejected) 等同,是一個(gè)語(yǔ)法糖。
let p = function () { return new Promise(function (resolve, reject) { resolve('開(kāi)始'); }); }; p().then(function (data) { console.log('1'); return new Promise(function (resolve, reject) { reject('錯(cuò)誤1'); }); }).then(function (data) { console.log('2'); return new Promise(function (resolve, reject) { reject('錯(cuò)誤2'); }); }).then(function (data) { console.log('3'); return new Promise(function (resolve, reject) { reject('錯(cuò)誤3'); }); }).catch(function (reason) { console.log(reason); });
注意,一旦操作中有錯(cuò)誤發(fā)生,則會(huì)進(jìn)入到catch中,后面的操作將不再執(zhí)行。
Promise對(duì)象內(nèi)部自帶了try catch,當(dāng)代碼運(yùn)行時(shí)錯(cuò)誤,會(huì)自動(dòng)以錯(cuò)誤對(duì)象為值reject,并最終被catch捕獲。
let p = function () { return new Promise(function (resolve, reject) { resolve('開(kāi)始'); }); }; p().then(function (data) { //注意這里打印了一個(gè)未定義的變量 console.log(a); }).catch(function (reason) { //這里會(huì)捕獲到錯(cuò)誤 console.log('rejected'); console.log(reason); });
Promise還提供了,all(),race(),reject(),resolve()等在構(gòu)造函數(shù)上的方法,調(diào)用這些方法并不需要實(shí)例化對(duì)象。
all()方法,可以讓我們并行的執(zhí)行異步操作,直到所有操作完成了,才執(zhí)行回調(diào)。
function fn1() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn1'); }, 1000); }); } function fn2() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn2'); }, 2000); }); } function fn3() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn3'); }, 3000); }); } //all會(huì)等待所有操作完成,會(huì)把所有操作的結(jié)果放到一個(gè)數(shù)組中,傳給then。 Promise.all([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
race()方法是誰(shuí)先處理完,就以誰(shuí)為準(zhǔn),把最先處理完的結(jié)果傳給then。
function fn1() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn1'); }, 1000); }); } function fn2() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn2'); }, 2000); }); } function fn3() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn3'); }, 3000); }); } //race是以誰(shuí)先處理完,就以誰(shuí)為準(zhǔn),fn1最先處理完,那fn1的結(jié)果會(huì)傳給then //注意這里fn2和fn3還是會(huì)執(zhí)行,不過(guò)不會(huì)進(jìn)入then了 Promise.race([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
reject()方法,返回一個(gè)帶有拒絕原因reason參數(shù)的Promise對(duì)象。
// Promise.reject('錯(cuò)誤') // 等同于 // new Promise(function(resolve, reject) { // reject('錯(cuò)誤'); // }); let p = Promise.reject('錯(cuò)誤'); p.then(function (data) { }).catch(function (reason) { console.log(reason); });
resolve()方法,根據(jù)傳入的值返回一個(gè)Promise對(duì)象。
//如果傳入的參數(shù)是普通值,則返回一個(gè)新Promise對(duì)象,并以該值resolve let p1 = Promise.resolve('OK'); p1.then(function (data) { console.log(data); }); //如果傳入的參數(shù)是一個(gè)Promise對(duì)象,則原封不動(dòng)的返回該P(yáng)romise對(duì)象 let obj = new Promise(function (resolve, reject) { resolve('我是Promise對(duì)象'); }); let p2 = Promise.resolve(obj); p2.then(function (data) { console.log(data); console.log(p2 === obj); }); //如果傳入的參數(shù)是一個(gè)thenable對(duì)象(帶有then方法), //會(huì)轉(zhuǎn)換成Promise對(duì)象,并執(zhí)行thenable對(duì)象的then方法 let then = { then(resolve, reject) { resolve('我是thenable對(duì)象'); } } let p3 = Promise.resolve(then); p3.then(function (data) { console.log(data); }); //如果什么參數(shù)都不傳入,則返回狀態(tài)為resolved的Promise對(duì)象 let p4 = Promise.resolve(); p4.then(function (data) { console.log(data); }).catch(function (reason) { console.log(reason); });
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具:http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行效果。
更多關(guān)于JavaScript相關(guān)內(nèi)容可查看本站專題:《JavaScript操作DOM技巧總結(jié)》、《JavaScript頁(yè)面元素操作技巧總結(jié)》、《JavaScript事件相關(guān)操作與技巧大全》、《JavaScript查找算法技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
微信小程序控制臺(tái)提示warning:Now you can provide attr "wx:key" for a "w
這篇文章主要介紹了微信小程序控制臺(tái)提示warning:Now you can provide attr "wx:key" for a "wx:for" to improve performance解決方法,簡(jiǎn)單分析了wx:for警告提示相關(guān)解決方法,需要的朋友可以參考下2019-02-02詳解JavaScript的Symbol類型、隱藏屬性、全局注冊(cè)表
這篇文章主要介紹了JavaScript的Symbol類型、隱藏屬性、全局注冊(cè)表,本文主要對(duì)其使用方法和使用場(chǎng)景做個(gè)簡(jiǎn)單的介紹,需要的朋友可以參考下2022-05-05JS自定義功能函數(shù)實(shí)現(xiàn)動(dòng)態(tài)添加網(wǎng)址參數(shù)修改網(wǎng)址參數(shù)值
本文自定義JS功能函數(shù)可動(dòng)態(tài)添加網(wǎng)址參數(shù),修改網(wǎng)址參數(shù)值,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-08-08JavaScript中的E-mail 地址格式驗(yàn)證
本文給大家分享JavaScript中的E-mail 地址格式驗(yàn)證,項(xiàng)目要求輸入的數(shù)據(jù)必須包含@符號(hào)和點(diǎn)號(hào)。代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2018-03-03深入了解JavaScript中邏輯賦值運(yùn)算符的應(yīng)用
邏輯賦值是對(duì)現(xiàn)有數(shù)學(xué)和二進(jìn)制邏輯運(yùn)算符的擴(kuò)展。我們先復(fù)習(xí)一下,然后看看把它們結(jié)合在一起能得到什么,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-11-11JavaScript代碼執(zhí)行的先后順序問(wèn)題
今天就給大家介紹一個(gè)特別基礎(chǔ)的東西,javascript中函數(shù)的一點(diǎn)兒小知識(shí)之js代碼的執(zhí)行順序問(wèn)題,需要的朋友參考下吧2017-10-10淺析Javascript的自動(dòng)分號(hào)插入(ASI)機(jī)制
我們大家都知道在寫(xiě)java和c時(shí),必須要在語(yǔ)句后加分號(hào),否則編譯通不過(guò)。而js不同,存在自動(dòng)分好插入機(jī)制,下文簡(jiǎn)稱ASI。它會(huì)給源代碼的 token 流自動(dòng)插入分號(hào)。下面這篇文章我們就來(lái)談?wù)凧avascript的自動(dòng)分號(hào)插入(ASI)機(jī)制。2016-09-09js實(shí)現(xiàn)表單多按鈕提交action的處理方法
這篇文章主要介紹了js實(shí)現(xiàn)表單多按鈕提交action的處理方法,需要的朋友可以參考下2015-10-10