先來說一下Promise的三種狀態(tài)
pending - 進行中
fulfilled - 成功
rejected - 失敗
Promise對象,可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)。
但Promise對象的狀態(tài)不受外界影響,Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失?。?,只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài),這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
狀態(tài)的改變(或者說決議)不可逆,一旦決議就不能再更改。
任何時候都可以得到這個結(jié)果,Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled 或者 從pending變?yōu)閞ejected,只要這兩種情況中的一種發(fā)生,其狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果,這時就稱為 resolved(已定型)。
如果改變已經(jīng)發(fā)生了,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果。
這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監(jiān)聽,是得不到結(jié)果的。
進階開始,讓我們手寫一個promise
概念: promise接受一個函數(shù) 有三種 狀態(tài) 倆個回調(diào)
寫一個構(gòu)造函數(shù)接收一個參數(shù) 有三種狀態(tài) 成功結(jié)果 失敗結(jié)果 成功回調(diào) 失敗 回調(diào)
構(gòu)造函數(shù)的原型有一個.then 方法 接收倆個參數(shù) 判斷狀態(tài) 如果成功調(diào)用 成功函數(shù) 失敗 調(diào)用失敗函數(shù) pending 就存起來。
代碼如下:
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// promise接受一個函數(shù) 有三種 狀態(tài) 倆個回調(diào)
// 寫一個構(gòu)造函數(shù)接收一個參數(shù) 有三種狀態(tài),此外還有:成功結(jié)果 失敗結(jié)果 成功回調(diào) 失敗回調(diào)
// 構(gòu)造函數(shù)的原型有一個.then 方法 接收倆個參數(shù) 判斷狀態(tài) 如果成功調(diào)用 成功函數(shù) ;失敗 調(diào)用失敗函數(shù) pending 就存起來
function Promise (executor) {
var _this = this
this.state = PENDING // 狀態(tài)
this.value = undefined // 成功結(jié)果
this.reason = undefined; // 失敗原因
this.onFulfilled = [];//成功的回調(diào)
this.onRejected = []; //失敗的回調(diào)
function resolve (value) {
if (_this.state === PENDING) {
_this.state = FULFILLED
_this.value = value
_this.onFulfilled.forEach(fn => fn(value))
}
}
function reject (reason) {
if (_this.state === PENDING) {
_this.state = REJECTED
_this.reason = reason
_this.onRejected.forEach(fn => fn(reason))
}
}
try {
executor(resolve, reject)
} catch (e) {}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.state === FULFILLED) {
typeof onFulfilled === 'function' && onFulfilled(_this.value)
}
if (this.state === REJECTED) {
typeof onRejected === 'function' && onRejected(_this.reason)
}
if(this.state === PENDING){
typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
typeof onRejected === 'function' && this.onRejected.push(onRejected)
}
}
// module.exports = Promise;
var p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(4)
}, 0)
})
p.then((res)=>{
//4 res
console.log(res, 'res')
})
p.then((res1)=>{
//4 res1
console.log(res1, 'res1')
})
一、對于resolve,reject簡單理解
我們先構(gòu)建一個Promise
//構(gòu)建Promise
var promise = new Promise(function (resolve, reject) {
if (/* 異步操作成功 */) {
resolve(data);
} else {
/* 異步操作失敗 */
reject(error);
}
});
這種方式類似構(gòu)建對象,使用new來構(gòu)建一個Promise。
Promise接受一個「函數(shù)」作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject。這兩個函數(shù)就是就是「回調(diào)函數(shù)」,由JavaScript引擎提供。
Promise實例生成以后,可以用then方法指定resolved狀態(tài)和reject狀態(tài)的回調(diào)函數(shù)。
//promise.then(onFulfilled, onRejected);
promise.then(function(data) {
// do something when success
}, function(error) {
// do something when failure
});
then方法會返回一個Promise。它有兩個參數(shù),分別為Promise從pending 變?yōu)?fulfilled和rejected時的回調(diào)函數(shù)(第二個參數(shù)非必選)。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)。
.catch()
該方法是.then(undefined, onRejected)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)。
promise.then(function(data) {
console.log('success');
}).catch(function(error) {
console.log('error', error);
});
/*******等同于*******/
promise.then(function(data) {
console.log('success');
}).then(undefined, function(error) {
console.log('error', error);
});
promise對象的錯誤,會一直向后傳遞,直到被捕獲。即錯誤總會被下一個catch所捕獲。then方法指定的回調(diào)函數(shù),若拋出錯誤,也會被下一個catch捕獲。catch中也能拋錯,則需要后面的catch來捕獲。
sendRequest('test.html').then(function(data1) {
//do something
}).then(function (data2) {
//do something
}).catch(function (error) {
//處理前面三個Promise產(chǎn)生的錯誤
});
此處要注意,promise一旦resolve(即成功狀態(tài))了再拋錯,也不會變?yōu)閞ejected(失敗狀態(tài)),也就不會被catch了,代碼如下:
var promise = new Promise(function(resolve, reject) {
resolve();
throw 'error';
});
promise.catch(function(e) {
console.log(e); //This is never called-永遠不會被觸發(fā)
});
如果沒有使用catch方法指定處理錯誤的回調(diào)函數(shù),Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應
關(guān)于promise中reject和catch的問題
一、reject后的東西,一定會進入then中的第二個回調(diào),如果then中沒有寫第二個回調(diào),則進入catch
var p1=new Promise((resolve,rej) => {
console.log('沒有resolve')
//throw new Error('手動返回錯誤')
rej('失敗了')
})
p1.then(data =>{
console.log('data::',data);
},err=> {
console.log('err::',err)
}).catch(
res => {
console.log('catch data::', res)
})
結(jié)果為:
沒有resolve
err:: 失敗了
then中沒有第二個回調(diào)的情況
var p1=new Promise((resolve,rej) => {
console.log('沒有resolve')
//throw new Error('手動返回錯誤')
rej('失敗了')
})
p1.then(data =>{
console.log('data::',data);
}).catch(
res => {
console.log('catch data::', res)
})
結(jié)果為:
沒有resolve
catch data:: 失敗了
二、resolve的東西,一定會進入then的第一個回調(diào),肯定不會進入catch
var p1=new Promise((resolve,rej) => {
console.log('resolve')
//throw new Error('手動返回錯誤')
resolve('成功了')
})
p1.then(data =>{
console.log('data::',data);
}).catch(
res => {
console.log('catch data::', res)
})
結(jié)果為:
resolve
data:: 成功了
不會進入catch的情況,只要resolve(即成功)了,就算拋出err,也不會進入catch
var p1=new Promise((resolve,rej) => {
console.log('resolve')
//throw new Error('手動返回錯誤')
resolve('成功了')
})
p1.catch(
res => {
console.log('catch data::', res)
})
結(jié)果:
resolve //即成功以后永遠不會進入catch
throw new Error 的情況和rej一樣,但是他倆只會有一個發(fā)生
另外,網(wǎng)絡異常(比如斷網(wǎng)),會直接進入catch而不會進入then的第二個回調(diào)