書接上回
12 catch 方法與異常穿透的實現(xiàn)
這個小節(jié)我們實現(xiàn)三個小細(xì)節(jié):
- catch方法的實現(xiàn)
- 異常穿透
- 值傳遞
catch方法的實現(xiàn)
它的作用是捕獲處理之前的錯誤.實現(xiàn)方式也非常簡單
//添加catch方法
PromiseA.prototype.catch = function (onRejected){
return this.then(undefined,onRejected)
}
我們只需要調(diào)用then
方法就可以了,因為catch
方法不需要成功的處理,只處理失敗,所以我們傳入失敗的回調(diào)就可以了.
異常穿透
什么是異常穿透呢? 看一下官方的例子:
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("error");
},100)
});
const result = p.then(value=>{
console.log(111)
}).then(value=>{
console.log(222)
}).then(value=>{
console.log(333)
}).catch(reason=>{
console.log(reason);
})
//error
可以看到報的錯誤error
已經(jīng)到達(dá)了catch
的回調(diào)函數(shù)中.而一旦換成我們自己的調(diào)用,就會報一下的錯誤:
TypeError: type is not a function
at callback (<anonymous>:65:30)
at Object.onRejected (<anonymous>:101:21)
在調(diào)用
onRejected:function (){
callback(onRejected);
}
的時候發(fā)生錯誤 ?表示type is not a function
也就是onRejected
這個回調(diào)函數(shù)沒有造成的.所以我們需要給它加上一個默認(rèn)的:
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//判斷回調(diào)函數(shù)參數(shù)
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason
}
}
//.....
添加上該方法以后,一旦發(fā)現(xiàn)有錯誤,它的處理就是向后拋,一知道最后.
測試用例:
let p = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
reject("error");
},100)
});
const result = p.then(value=>{
console.log(111)
}).then(value=>{
console.log(222)
}).then(value=>{
console.log(333)
}).catch(reason=>{
console.log(reason);
})
//error
或者中間拋出錯誤:
let p = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
resolve("ok");
},100)
});
const result = p.then(value=>{
console.log(111)
}).then(value=>{
throw "error"
}).then(value=>{
console.log(333)
}).catch(reason=>{
console.log(reason);
})
//輸出
//111
//error
值傳遞
實際上要達(dá)到的效果是 then
方法中不寫回調(diào)函數(shù)也可以傳遞到后面,
所以和上面的類似,我們添加一個默認(rèn)的方法就可以了.
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//判斷回調(diào)函數(shù)參數(shù)
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason
}
}
//--------------修改代碼的地方----------
if(typeof onResolved !== "function"){
onResolved = value => value;
}
//--------------修改代碼的地方----------
//...
測試用例:
let p = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
resolve("ok");
},100)
});
const result = p.then().then(value=>{
console.log(value)
})
//輸出
ok
可以看到我們中間的then
方法雖然沒有設(shè)置回調(diào)函數(shù),但是還是把值傳遞到后面去了.
13.Promise.resolve 的封裝
這個方法的特性在之前的小記中有記錄,它返回一個Promise對象.
而這個Promise對象的狀態(tài)取決于傳遞給它的參數(shù).看到這里是不是感覺耳熟,是的,和上面的情況一樣.
- 返回非Promise對象的,比如123,ok,不返回就是undefined,那么它默認(rèn)會執(zhí)行返回成功的Promise對象,
- 返回Promise對象的,則由這個對象決定狀態(tài),如果這個這個對象是成功的,那么外部result就是成功,如果失敗的,那么外部就是失敗的.
- 如果拋出錯誤,那么外部對象就是失敗的.
所以我們可以這樣實現(xiàn):
PromiseA.resolve = function (value){
//返回Promise
return new PromiseA((resolve,reject)=>{
try{
if(value instanceof PromiseA){
value.then(v=>{
resolve(v);
},r=>{
reject(r);
})
}else{
resolve(value);
}
}catch (e){
reject(e);
}
})
}
測試用例:
let p = PromiseA.resolve( new PromiseA((resolve,reject)=>{
reject("error");
}));
let p1 = PromiseA.resolve(new PromiseA((resolve,reject)=>{
resolve("OK");
}))
let p2 = PromiseA.resolve(111);
p.catch(e=>console.log(e))
console.log(p)
console.log(p1)
console.log(p2)
//輸出結(jié)果
error
PromiseA {
PromiseState: 'rejected',
PromiseResult: 'error',
callbacks: []
}
PromiseA {
PromiseState: 'fulfilled',
PromiseResult: 'OK',
callbacks: []
}
PromiseA {
PromiseState: 'fulfilled',
PromiseResult: 111,
callbacks: []
}
13.Promise.reject 的封裝
它和resolve
的區(qū)別就是 無論是什么情況下,它的返回結(jié)果的Promise
都是失敗的情況的.
//添加 reject 方法
PromiseA.reject = function (value){
//返回Promise
return new PromiseA((resolve,reject)=>{
reject(value)
})
}
14.Promise.all 的封裝實現(xiàn)
它的特性是什么是什么? 它的參數(shù)是一個數(shù)組,里面是promise對象.
只有所有的promise對象都成功,它才會成功,但是如果其中有一個失敗,那么結(jié)果就會失敗.
下面是實現(xiàn)方法:
//添加 all 方法
PromiseA.all = function (promises){
//返回結(jié)果為Promise的對象
return new PromiseA((resolve,reject)=>{
//遍歷
let count = 0;
let arr = [];
for(let i = 0;i<promises.length;i++){
promises[i].then(v=>{
//得知對象的狀態(tài)是成功
//每個promise對象都成功
count++;
//將當(dāng)前promise對象成功的結(jié)果 存入到數(shù)組中
// arr.push(v);
arr[i] = v;
if(count === promises.length){
resolve(arr);
}
},r=>{
reject(r);
});
}
})
}
測試用例: 成功的情況
let p = PromiseA.resolve("ok");
let p1 = PromiseA.resolve("111");
let p2 = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
resolve("ccc")
},1000)
})
let p3 = PromiseA.all([p,p1,p2]);
p3.then((data)=>{
console.log(data);
})
輸出結(jié)果:
[ 'ok', '111', 'ccc' ]
測試用例:失敗的情況
let p = PromiseA.resolve("ok");
let p1 = PromiseA.resolve("111");
let p2 = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
reject("error");
},1000)
})
let p3 = PromiseA.race([p,p1,p2]);
p3.catch(e=>{
console.log(e)
})
//輸出
//error
15 Promise.race 的封裝
它的特性是,只要其中有一個成功,那么就成功,并返回這個結(jié)果,
如果其中有一個就失敗了,那么就失敗了,返回失敗的結(jié)果,有別去上面的情況.不需要計數(shù) 直接有結(jié)果就調(diào)用.
PromiseA.race = function (promises){
return new PromiseA((resolve,reject)=>{
for(let i = 0;i<promises.length;i++){
promises[i].then(v=>{
resolve(v);
},r=>{
reject(r);
});
}
})
}
測試用例:
let p = PromiseA.resolve("ok");
let p1 = PromiseA.resolve("111");
let p2 = new PromiseA((resolve,reject)=>{
setTimeout(()=>{
reject("111");
},1000)
})
let p3 = PromiseA.race([p,p1,p2]);
p3.then(v=>{
console.log(v)
})
//輸出
ok
16. 回調(diào)函數(shù)時異步執(zhí)行的
這里附上完整的代碼:
function PromiseA(executor){
//添加屬性
this.PromiseState = "pending";
this.PromiseResult = null;
this.callbacks = [];
//預(yù)先保存實例對象的this值
const self = this;
//resolve函數(shù)
function resolve(data){
//判斷狀態(tài)
if(self.PromiseState !== "pending"){
return ;
}
//1.修改對象的狀態(tài)(PromiseState)
self.PromiseState = "fulfilled";
//2.設(shè)置對象的結(jié)果值(PromiseResult)
self.PromiseResult = data;
//微任務(wù)執(zhí)行回調(diào)
queueMicrotask(()=> {
//調(diào)用成功的回調(diào)函數(shù)
self.callbacks.forEach(item => {
item.onResolved(data);
})
})
}
function reject(data){
//判斷狀態(tài)
if(self.PromiseState !== "pending"){
return ;
}
//1.修改對象的狀態(tài)(PromiseState)
self.PromiseState = "rejected";
//2.設(shè)置對象的結(jié)果值(PromiseResult)
self.PromiseResult = data;
//微任務(wù)執(zhí)行回調(diào)
queueMicrotask(()=> {
//調(diào)用失敗的回調(diào)函數(shù)
self.callbacks.forEach(item => {
item.onRejected(data);
})
}
)
}
//處理 throw 拋出的錯誤
try{
//同步調(diào)用一下
executor(resolve,reject);
}catch (e){
//通過調(diào)用reject函數(shù),它的內(nèi)部可以修改狀態(tài)的和賦值
//所以我們這里可以把錯誤直接傳進(jìn)去就可以了.
reject(e);
}
}
//添加 then 方法
PromiseA.prototype.then = function (onResolved,onRejected){
const self = this;
//判斷回調(diào)函數(shù)參數(shù)
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason
}
}
if(typeof onResolved !== "function"){
onResolved = value => value;
}
//這個就是返回外部的結(jié)果Promise ,它的內(nèi)部狀態(tài)由 then方法的回調(diào)決定
return new PromiseA((resolve,reject)=>{
//抽象成一個函數(shù)
function callback(type){
try{
let result = type(self.PromiseResult);
//判斷 result 是 Promise 對象
if(result instanceof PromiseA){
//如果是Promise對象,我們需要知道這個對象的狀態(tài)是成功還是失敗的?
//Promise對象如果成功,它一定會回調(diào) onResolved 失敗 會回調(diào) onRejected
result.then(v=>{
//在它的內(nèi)部調(diào)用 resolve 來修改外部 我們創(chuàng)建的那個Promise對象的狀態(tài)
resolve(v);
},r=>{
reject(r);
})
}else{
//非Promise 數(shù)據(jù) 則成功,通過調(diào)用resolve來修改
resolve(result);
}
}catch (e){
reject(e);
}
}
//調(diào)用 成功 回調(diào)函數(shù)
if(self.PromiseState === "fulfilled"){
queueMicrotask(()=> {
callback(onResolved);
})
}
//調(diào)用失敗的回調(diào)函數(shù)
if(self.PromiseState === "rejected"){
queueMicrotask(()=> {
callback(onRejected);
})
}
//添加pending狀態(tài)的處理
if(self.PromiseState === "pending"){
//保存回調(diào)函數(shù)
self.callbacks.push({
onResolved:function (){
queueMicrotask(()=> {
callback(onResolved);
});
},
onRejected:function (){
queueMicrotask(()=> {
callback(onRejected);
})
}
});
}
})
}
//添加catch方法
PromiseA.prototype.catch = function (onRejected){
return this.then(undefined,onRejected)
}
//添加 resolve 方法
PromiseA.resolve = function (value){
//返回Promise
return new PromiseA((resolve,reject)=>{
try{
if(value instanceof PromiseA){
value.then(v=>{
resolve(v);
},r=>{
reject(r);
})
}else{
resolve(value);
}
}catch (e){
reject(e);
}
})
}
//添加 reject 方法
PromiseA.reject = function (value){
//返回Promise
return new PromiseA((resolve,reject)=>{
try{
reject(value)
}catch (e){
reject(e);
}
})
}
//添加 all 方法
PromiseA.all = function (promises){
//返回結(jié)果為Promise的對象
return new PromiseA((resolve,reject)=>{
//遍歷
let count = 0;
let arr = [];
for(let i = 0;i<promises.length;i++){
promises[i].then(v=>{
//得知對象的狀態(tài)是成功
//每個promise對象都成功
count++;
//將當(dāng)前promise對象成功的結(jié)果 存入到數(shù)組中
// arr.push(v);
arr[i] = v;
if(count === promises.length){
resolve(arr);
}
},r=>{
reject(r);
});
}
})
}
// 添加race方法
PromiseA.race = function (promises){
return new PromiseA((resolve,reject)=>{
for(let i = 0;i<promises.length;i++){
promises[i].then(v=>{
resolve(v);
},r=>{
reject(r);
});
}
})
}
測試用例:
let p = new PromiseA((resolve,reject)=>{
console.log('111')
resolve("222")
})
console.log(333)
p.then((value)=>{
console.log(value)
})
輸出結(jié)果:
111
333
222