文章目录
Promise
Promise介绍
1. Promise是异步编程的一种解决方案,比传统的解决方案—回调函数和事件—更合理;
2. Promise其实就是一个容器,里面保存了当异步事件调用后可能发生的结果;
Promise的三种状态
3. Promise对象是一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有当异步操作结束后,才能确定当前的状态,其他操作无法改变其状态;并且状态一旦发生改变,便不会再发生改变,装填的改变只有两种可能:从pending改变为fulfilled—异步操作成功;从pending改变为rejected—异步操作失败。一旦状态发生了改变,后面再对Promise对象添加回调函数,也会立即得到该结果
- pending:等待状态,比如正在进行网络请求,或者定时器还没到时间
- fulfill:成功状态,当主动回调resolve时,就从pending改变为fulfill状态,并回调.then()
- reject:拒绝状态,当主动回调reject后,从pending改变为reject状态,并回调.catch()
4. Promise的回调函数中有两个参数resolve和reject,这是由JavaScript自身提供,当异步操作获得的结果,无论早晚都没关系,它的回调将是以下回调之一:
- resolve(value)—如果任务成功完成该并带有结果value
- reject(error)—如果出现了error,返回error,error即为error对象
let promise = new Promise((resolve, reject)=>{
resolve('success');
reject(new Error('failed')); //将被会忽略
setTimeout(()=>reslove('done'));//也会被忽略
})
promise的基本使用:
resolve和reject是两个函数,通常情况下,根据请求数据的成功与否来决定调用哪一个函数。
- 如果成功,那就调用resolve(data),然后.then会被回调
- 如果失败,那就调用reject(error),然后.catch会被回调
const promise = new Promise((reslove, reject)=>{
setTimeout(()=>{
reslove('success');
reject('failed');
},1000)
}).then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
Promise链式调用
无论是then还是catch,最后都可以返回一个Promise对象,因此可以对Promise来链式调用,同时可以用Promise来包装一下数据再返回:
- Promise.resolve():将数据包装成Promise对象,并在内部回调resolve()函数,直接返回数据将默认是这种形式
- Promise.reject():将数据包装成Promise对象,并在内部回调reject函数
const promise = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('success');
},1000)
}).then(message=>{
console.log(message); //success
return Promise.resolve(message + '111');
}).then(message=>{
console.log(message); //success111
return message + '222'; //若返回的是resolve,则可以直接返回数据
}).then(message=>{
console.log(message); //success111222
return Promise.reject(message + 'error'); //由于这里是reject,因此不会执行下面的.then了,而是执行catch
}).then(message=>{
console.log(message); //没有输出,不会执行
return message + '333';
}).catch(message=>{
console.log(message); //success111222error
}).finally(()=>{ //finally是不管promise的状态如何,都会执行的操作
console.log('promise is finished');
})
Promise方法
Promise.prototype.*为Promise实例的方法
Promise.*为Promise对象的方法
Promise.prototype.then()
.then方法是为Promise实例添加状态改变时的回调函数,其参数都是函数:第一个参数是resolve状态的回调函数,第二个参数(可选)是reject状态的回调函数。不过尽量少使用第二个参数,而是使用catch方法
then方法返回的是一个新的Promise实例,因此可以进行链式调用(如上面的代码)
const promise = new Promise((resolve,reject)=>{
resolve('success'); //状态一旦确定就不会再改变
reject('error'); //因此该状态不会发生
}).then((message)=>{
console.log(message); //success
return message + '1111'; //返回的将是一个新的promise实例,简写形式默认是Promise.resolve()
},(error)=>{
console.log(error); //不会执行
}).then(
message => console.log(message); //上一个then函数中的返回值作为参数传入下一个then函数的回调函数中
)
Promise.prototype.catch()
.catch()方法是.then(null, reject)或.then(undefined,reject)的别名,相当于是then方法的第二个参数的回调函数,用于当异步操作发生错误时的回调函数
const promise = new Promise((resolve,reject)=>{
reject('error了');
}).catch(
error => console.log(error); //error了
)
//等同于
const promise = new Promise((resolve,reject)=>{
reject('error了');
}).then(
null,
error => console.log(error) //error了
)
若不使用catch,Promise对象抛出的错误不会传递到外层代码,也就是说不会影响到外部代码的运行。因此一般情况下,Promise对象要跟上一个catch方法来捕获错误,如果有错就捕获,如果没错就继续执行后面的代码
const promise = new Promise((resolve,reject)=>{
resolve(x*2); //会报错,因为x未定义
}).then(
()=>console.log('programmer is finished')
)
setTimeout(()=>{console.log('aaaaa')},3000)
//Uncaught (in promise) ReferenceError: x is not defined
//aaaaa 虽然报错,但是也会继续执行后面的代码
Promise.prototype.finally()
.finally()方法用于表示Promise对象最后的状态,不管异步操作成功与否,都会执行该方法。
并且finally方法的回调函数不接受任何参数,该方法与状态无关,不管Promise是啥状态,最后都会执行
const promise = new Promise((resolve, reject)=>{
resolve('success');
}).then(
message => console.log(message)
).catch(
error => console.log(error)
).finally(
()=> console.log('finished')
)
finally方法其实是then方法的特例
const promise = new Promise((resolve, reject)=>{
resolve('success');
})
promise.finally(
()=>{console.log('finished');}
)
//等同于
promise.then(
() => console.log('finished'),
() => console.log('finished')
)
Promise.all()
.all()方法是将多个Promise实例,组合成一个新的Promise实例
const p1 = new Promise((res,rej)=>{});
const p2 = new Promise((res,rej)=>{});
const p3 = new Promise((res,rej)=>{});
const promise = Promise.all([p1, p2, p3]);
Promise.all()方法接受一个数组作为参数,p1,p2,p3都是Promise实例。若不是,则会调用Promise.resolve方法,将参数转换为Promise实例,再进一步处理。当然,all()方法的参数不一定是数组,只要具备Iterator接口即可。
而promise的状态由p1,p2,p3共同决定的,
若p1,p2,p3的状态都是fulfilled,promise的状态才会是fulfilled,并且此时的p1,p2,p3的返回值组成一个数组,传递给promise的回调函数
若p1,p2,p3中有一个的状态是reject,那promise的状态就变成了rejected,并且此时被reject的实例的返回值,传递给promise的回调函数
const p1 = new Promise((resolve,reject)=>{
resolve('resolve1');
})
.then(res => res)
.catch(err => err);
const p2 = new Promise((resolve,reject)=>{
throw new Error('报错了');
})
.then(res => res)
.catch(err => err);
Promise.all([p1,p2])
.then(res=>console.log(res))
.catch(err => console.log(err))
//["resolve1", Error: 报错了]
/*p1是resolved状态,p2首先是rejected状态,但是p2有自己的catch
方法,会返回一个新的Promise实例,并且默认是resolved方法,所以最
后返回的是resolved,因此all方法的参数的两个promise实例都是
resolved,因此会调用then方法*/
const p1 = new Promise((resolve,reject)=>{
resolve('resolve1');
})
.then(res => res)
.catch(err => err);
const p2 = new Promise((resolve,reject)=>{
throw new Error('报错了');
})
.then(res => res)
.catch(err =>{
return Promise.reject(err); //手动返回reject,所以p2最终状态为resolved
});
Promise.all([p1,p2])
.then(res=>console.log(res))
.catch(err => console.log(err))
//Error: 报错了
//有一个是reject,因此就返回对应reject的返回值
Promise.prototype.race()
.race()方法.all()方法类似,将多个Promise实例包装成一个Promise实例
const p = Promise.race([p1,p2,p3]);
p1,p2,p3中只要有一个实例状态先改变,p的状态也就跟着改变,先改变状态的p的返回值,就传递给p的回调函数
Promise.resolve()、Promise.reject()
Promise.resolve()和Promise.reject()都是将现有对象转换为Promise对象
Promise.resolve('bar');
//相当于
new Promise(resolve=>resolve('bar'))
Promise.reject('bar');
//相当于
new Promise(reject=>reject('bar'))
try…catch
try…catch是一种错误处理,当程序遇到错误时,就会在控制台输出错误,并停止运行,这可能不太合理。因此使用一种语法结构try…catch,程序即使发生了错误,也能进行 更合理的操作,而不会立即停止
//如果try中的代码没有错误,则catch中的代码不会执行;若出现错误,try中的代码立即停止执行,跳转到catch中的代码
try{
//执行的代码
}catch(err){
//错误捕获
}
try…catch是同步工作的
如果在try中的代码发生了异常,假如在setTimeout函数中,try…catch不会捕获到异常
try{
setTimeout(()=>{
console.log(a); //程序到这就停止了,因为是同步执行的,而不会去执行catch了
},2000)
}catch(e){
console.log('error了')
}
//将try...catch函数放到setTimeout函数中,这样就能捕获错误了
setTimeout(()=>{
try{
console.log(a);
}catch(err){
console.log('error了');
}
},2000)
try…catch…finally
try…catch还有一个代码子句,就是finally,它在所有情况下都会执行
try {
//尝试执行的代码
console.log('try');
} catch (e) {
//处理error
console.log( 'catch' );
} finally {
//总是会执行的代码
console.log( 'finally' );
}
Error对象
如catch中的error参数,这个error可以用任何变量代替,这是一个Error对象
对于所有的Error对象,都有如下属性
- name:对于一个未定义变量的错误,name是’ReferenceError’
- message:对error的详细描述
- stack: 当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息
let error = new Error('this is an error');
console.log(error.name); //Error
console.log(eror.message); //this is an error
throw操作符
throw操作符可以生成一个自定义的error对象
const promise = new Promise((resolve, reject)=>{
throw new Error('failed'); //相当于reject
}).catch((error)=>{
console.log(error); //Error: failed
});