怎么在ES6中使用Promise?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)成立與2013年,先為開陽等服務建站,開陽等地企業(yè),進行企業(yè)商務咨詢服務。為開陽企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。在javascript中,代碼是單線程執(zhí)行的,對于一些比較耗時的IO操作,都是通過異步回調(diào)函數(shù)來實現(xiàn)的。
但是這樣會存在一個問題,當下一個的操作需要上一個操作的結(jié)果時,我們只能把代碼嵌到上一個操作的回調(diào)函數(shù)里,這樣一層嵌一層,最終形成回調(diào)地獄。
$.get('/login.php', function (login) { $.get('/user.php', function (user) { $.get('/info.php', function (info) { //代碼就這樣一層嵌一層,不夠直觀,維護也麻煩 }); }); });
為了解決這種問題,ES6中就提供了Promise方法來解決這種問題。
Promise是一個構(gòu)造函數(shù),通過它,我們可以創(chuàng)建一個Promise實例對象。
let p = new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); });
Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),這個函數(shù)有兩個參數(shù),resolve和reject。
resolve函數(shù)是將Promise的狀態(tài)設置為fulfilled(完成),reject函數(shù)是將Promise的狀態(tài)設置為rejected(失敗)。
上述代碼,我們并沒有進行任何調(diào)用,當運行時,間隔1秒后輸出了'OK'。所以這里需要注意,我們通常使用Promise時,需要在外層再包裹一層函數(shù)。
let p = function () { return new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); }); }; p();
上面的代碼p();返回的是一個Promise實例對象,Promise對象上有 then() , catch() , finally() 方法。
then方法有兩個參數(shù),onFulfilled和onRejected,都是函數(shù)。
onFulfilled用于接收resolve方法傳遞過來的數(shù)據(jù),onRejected用于接收reject方法傳遞過來的數(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()方法總是會返回一個Promise實例,這樣我們就可以一直調(diào)用then()。
在then方法中,你既可以return 一個具體的值 ,還可以return 一個Promise對象。
如果直接return的是一個數(shù)據(jù),那then方法會返回一個新Promise對象,并以該數(shù)據(jù)進行resolve。
let p = function () { return new Promise(function (resolve, reject) { resolve(1); }); }; p().then(function (data) { console.log(`第 ${data} 次調(diào)用`); //注意這里直接返回的值 //then會創(chuàng)建一個新的Promise對象,并且以返回的值進行resolve //那么該值會被下面的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; });
如果返回的是一個Promise對象,請看下面代碼。
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); }); });
其實效果與直接返回值的是一樣的。
即然then()可以進行鏈式操作,那我們最早之前的回調(diào)地獄寫法,就可以通過它進行改進了。
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ù),傳入到下一個處理中。 return user(data); }).then(function (data) { console.log('處理user'); //把user異步處理獲取的數(shù)據(jù),傳入到下一個處理中。 return info(data); }).then(function (data) { console.log('處理info'); });
這樣修改后,回調(diào)地獄層層嵌套的結(jié)構(gòu)就變的清晰多了。上述代碼是偽代碼。
Promise對象還有一個catch方法,用于捕獲錯誤,該方法與 then(null, onRejected) 等同,是一個語法糖。
let p = function () { return new Promise(function (resolve, reject) { resolve('開始'); }); }; p().then(function (data) { console.log('1'); return new Promise(function (resolve, reject) { reject('錯誤1'); }); }).then(function (data) { console.log('2'); return new Promise(function (resolve, reject) { reject('錯誤2'); }); }).then(function (data) { console.log('3'); return new Promise(function (resolve, reject) { reject('錯誤3'); }); }).catch(function (reason) { console.log(reason); });
注意,一旦操作中有錯誤發(fā)生,則會進入到catch中,后面的操作將不再執(zhí)行。
Promise對象內(nèi)部自帶了try catch,當代碼運行時錯誤,會自動以錯誤對象為值reject,并最終被catch捕獲。
let p = function () { return new Promise(function (resolve, reject) { resolve('開始'); }); }; p().then(function (data) { //注意這里打印了一個未定義的變量 console.log(a); }).catch(function (reason) { //這里會捕獲到錯誤 console.log('rejected'); console.log(reason); });
Promise還提供了,all(),race(),reject(),resolve()等在構(gòu)造函數(shù)上的方法,調(diào)用這些方法并不需要實例化對象。
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會等待所有操作完成,會把所有操作的結(jié)果放到一個數(shù)組中,傳給then。 Promise.all([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
race()方法是誰先處理完,就以誰為準,把最先處理完的結(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是以誰先處理完,就以誰為準,fn1最先處理完,那fn1的結(jié)果會傳給then //注意這里fn2和fn3還是會執(zhí)行,不過不會進入then了 Promise.race([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
reject()方法,返回一個帶有拒絕原因reason參數(shù)的Promise對象。
// Promise.reject('錯誤') // 等同于 // new Promise(function(resolve, reject) { // reject('錯誤'); // }); let p = Promise.reject('錯誤'); p.then(function (data) { }).catch(function (reason) { console.log(reason); });
resolve()方法,根據(jù)傳入的值返回一個Promise對象。
//如果傳入的參數(shù)是普通值,則返回一個新Promise對象,并以該值resolve let p1 = Promise.resolve('OK'); p1.then(function (data) { console.log(data); }); //如果傳入的參數(shù)是一個Promise對象,則原封不動的返回該Promise對象 let obj = new Promise(function (resolve, reject) { resolve('我是Promise對象'); }); let p2 = Promise.resolve(obj); p2.then(function (data) { console.log(data); console.log(p2 === obj); }); //如果傳入的參數(shù)是一個thenable對象(帶有then方法), //會轉(zhuǎn)換成Promise對象,并執(zhí)行thenable對象的then方法 let then = { then(resolve, reject) { resolve('我是thenable對象'); } } let p3 = Promise.resolve(then); p3.then(function (data) { console.log(data); }); //如果什么參數(shù)都不傳入,則返回狀態(tài)為resolved的Promise對象 let p4 = Promise.resolve(); p4.then(function (data) { console.log(data); }).catch(function (reason) { console.log(reason); });
看完上述內(nèi)容,你們掌握怎么在ES6中使用Promise的方法了嗎?如果還想學到更多技能或想了解更多相關內(nèi)容,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!