1.1、promise是什么?
(1)抽象表达
-
promise是一门新的技术(ES6规范)
-
promise是js进行异步编程新解决方案 备注:旧方案是单纯的函数回调
(2)具体表达
-
从语法上来说:promise是一个构造函数
-
从功能上来说:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
1.2、为什么使用promise?
(1)指定回调函数的方式更加的灵活
-
旧的:必须在启动异步任务前指定
-
promise:启动异步任务=>返回promise对象=>给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
(2)支持链式调用,可以解决回调地狱问题(面试经常问到)
-
什么是地狱回调:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行条件
-
回调地狱的缺点:不便于阅读;不便于异常处理。
-
解决方案:promise链式调用
1.3、promise体验
//生成一个随机数
function rand(m,n){
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
};
// 获取元素对象
let eventbtn = document.querySelector("#btn");
//=给元素对象添加点击事件
eventbtn.addEventListener('click',function (){
// 普通方式
// 添加定时器
// setTimeout(()=>{
// let n = rand(1,100);
// if (n<=30){
// alert("恭喜中奖")
// }else {
// alert('很遗憾,再接再厉')
// }
// },1000);
// promise方式实现-----promise是一个构造函数 可以对象实例化 promise的参数是一个函数,函数有两个形参resolve解决, reject拒绝
let m = new Promise((resolve, reject)=>{
setTimeout(()=>{
let n = rand(1,100);
if (n<=30){
resolve() //将promise对象的状态设置为 成功
}else {
reject() //将promise对象的状态设置为 失败
}
},1000);
});
m.then(()=>{
alert("恭喜中奖")
},()=>{
alert('很遗憾,再接再厉')
})
});
1.4、使用promise封装fs读取文件
const fs require('fs')
//回调函数形式
fs.readFile('./resource/context.txt',(err.data)=>{
//如果出错 则抛出错误
if(err) throw err;
//输出文件内容
data.toString()
})
//promise形式
let m = new Promise((resolve, reject)=>{
fs.readFile('./resource/context.txt',(err.data)=>{
//如果出错 则抛出错误
if(err) reject(err);
//否则 输出文件内容
resolve(data)
})
});
//调用then方法 指定回调函数
m.then((value)=>{
value.toString();
},(reason)=>{
console.log(reason)
})
1.5、promise对象状态属性的介绍
1.5.1 实力状态中的一个属性 PromiseState
(1)三种状态 分别为 pending、resolved/fulfilled、rejected
(2)状态改变的时候只有两种可能,且一个promise对象只改变一次
修改promise对象状态的方法:
-
由resolvet() 将pending=>resolved/fulfilled
-
由reject() 将pending=>rejected
-
抛出错误 如throw ‘出错了’
1.6、promise对象结果值属性介绍
1.6.1 promise对象的值
(1)实例对象中的另一个属性 PromiseResult;保存着异步任务 成功/失败 的结果
(2)可修改PromiseResult 值的有两个函数
-
resolved
-
rejected
1.7、promise工作流程
(1)先创建一个promise实例
(2)在promise对象中封装一些异步操作
(3)异步任务执行成功后,执行resolve(),resolve()回调则将promise对象状态设置为resolved;再调then()方法(指定回调函数的方法),调用第一个回调函数(参数),然后返回一个新的promise对象
(4)异步任务执行失败后,执行reject()函数,reject()将promise设置为rejected状态;再调用then()方法中的第二个回调函数,返回一个新的promise对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xlezB9jg-1646962959967)(C:\Users\qctc\AppData\Roaming\Typora\typora-user-images\image-20220307162158216.png)]
1.8、promise 的resolve()和reject()方法
(1)resolve()方法:(value)=>{};value 为成功的数据或者对象
说明:返回一个成功/或者失败的对象
(2)reject()方法:(reason)=>{} reason为失败的原因;
说明:返回一个失败的promise对象
1.9、改变promise状态和指定回调函数的先后顺序?
(1)都有可能,正常情况下是先指定回调函数再改变状态,但也可以先改变状态再指定回调函数。
(2)如何先改变状态再指定回调函数?
-
在执行器中直接调用resolve()/reject()
-
延迟更长时间再调用then()方法
(3)什么时候才能获取到数据?
-
如果先指定回调函数,当状态发生改变时,回调函数就会调用,得到数据。
-
如果先改变状态,那当指定回调函数,回调函数就会调用,得到数据。
1.10、promise如何串连多个操作任务?
(1)promise的then()返回一个新的promise,可以开成then的链式调用
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('ok')
},1000)
});
p.then((value)=>{
//返回一个promise对象
return new Promise((resolve,reject)=>{
resolve('success')
})
}).then(value=>{
console.log(value)// value 为 success
}).then(value=>{
console.log(value)//value 为undefined 因为上一个then()方法没有返回值
})
(2)通过then()的链式调用串连多个同步/异步任务
1.11、关键问题 promise异常穿透?
(1)当使用promise的then链式调用时,可以在最后指定失败的回调
(2)前面任何操作出现了异常,都会传到最后失败的回调处理
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('ok')
},1000)
});
p.then((value)=>{
//console.log(value)
throw '出错了'
}).then(value=>{
console.log(222)// value 为 success
}).then(value=>{
console.log(333)//value 为undefined 因为上一个then()方法没有返回值
}).catch(reason=>{//直接穿过前面的两个then 执行catch
console.log(reason)
})
1.12、如何中断promise链?
(1)返回一个pending状态的promise对象
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('ok')
},1000)
});
p.then((value)=>{
return new Promise(()=>{})//返回pending状态 promise对象 解决中断promise链的唯一方法
}).then(value=>{
console.log(222)// value 为 success
}).then(value=>{
console.log(333)//value 为undefined 因为上一个then()方法没有返回值
}).catch(reason=>{//直接穿过前面的两个then 执行catch
console.log(reason)
})
1.13、promise自定义封装
let p = new Promise((resolve,reject)=>{
// resolve('ok')
// reject('出错了');
throw '出错' //抛出异常 改变promise状态 rejected
});
console.log(p)
p.then(value=>{
console.log("value==",value)
},reason=>{
console.log("reason==",reason)
})
(1)初始结构搭建
//声明构造函数
function Promise(executor){//executor执行器参数
}
//添加then()方法
Promise.prototype.then = function (onResolved,onRejected){
}
(2)resolve和reject结构搭建
//声明构造函数
function Promise(executor){//executor执行器参数
//resolve函数
function resolve(data){
};
//reject函数
function reject(data){
}
executor(resolve,reject);
}
//添加then()方法
Promise.prototype.then = function (onResolved,onRejected){
}
(3)resolve和reject代码实现
//声明构造函数
function Promise(executor){//executor执行器参数
//最开始的promise状态
this.PromiseState = 'pending'
//最开始的promise值
this.PromiseResult = null;
//保存promise实例对象的this值
const that = this;
//resolve函数
function resolve(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'resolved'
//修改对象的值
that.PromiseResult = data;
//调用成功的回调函数
};
//reject函数
function reject(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'rejected'
//修改对象的值
that.PromiseResult = data;
}
executor(resolve,reject);
}
//添加then()方法
Promise.prototype.then = function (onResolved,onRejected){
}
(4)throw抛出异常改变promise状态
(5)then方法执行回调
//添加then()方法 指定函数处理promise结果返回值
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState == 'fulfilled'){
onResolved(this.PromiseResult)
}
if (this.PromiseState == 'rejected'){
onRejected(this.PromiseResult)
}
}
(6)异步任务回调的执行
//声明构造函数
function Promise(executor){//executor执行器参数
//最开始的promise状态
this.PromiseState = 'pending'
//最开始的promise值
this.PromiseResult = null;
//保存实例对象的this值
const that = this;
//声明一个属性
this.callback = {};
//resolve函数
function resolve(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'resolved'
//修改对象的值
that.PromiseResult = data;
//调用成功的回调函数
if (that.callback.onResolved){
that.callback.onResolved(data)
}
};
//reject函数
function reject(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'rejected'
//修改对象的值
that.PromiseResult = data;
//执行失败回调
if(that.callback.onRejected){
that.callback.onRejected(data)
}
}
try{
//同步调用 执行器函数
executor(resolve,reject);
}catch(err){
//修改promise状态 为失败rejected
reject(err)
}
}
//添加then()方法 指定函数处理promise结果返回值
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState == 'fulfilled'){
onResolved(this.PromiseResult)
}
if (this.PromiseState == 'rejected'){
onRejected(this.PromiseResult)
}
if (this.PromiseState == 'pending'){//promise 状态为pending的时候执行
// 保存回调函数
this.callback = {
onResolved:onResolved,
onRejected:onRejected
}
}
}
(7)指定多个回调的实现
思路:先声明一个回调数组callbacks;在then的方法中保存回调函数 将{onResolved:onResolved,onRejected:onRejected}push到callbacks中;在resolve或者reject函数中,遍历调用成功/失败的回调函数
//声明构造函数
function Promise(executor){//executor执行器参数
//最开始的promise状态
this.PromiseState = 'pending'
//最开始的promise值
this.PromiseResult = null;
//保存实例对象的this值
const that = this;
//声明一个属性
this.callback = [];
//resolve函数
function resolve(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'resolved'
//修改对象的值
that.PromiseResult = data;
//遍历调用成功的回调函数
that.callback.forEach(item=>{
item.onResolved(data)
})
};
//reject函数
function reject(data){
//判断状态是否为pending
if(that.PromiseState !== 'pending') return
//修改对象的状态
that.PromiseState = 'rejected'
//修改对象的值
that.PromiseResult = data;
//
//遍历执行失败回调
that.callback.forEach(item=>{
item.onRejected(data)
})
}
try{
//同步调用 执行器函数
executor(resolve,reject);
}catch(err){
//修改promise状态 为失败rejected
reject(err)
}
}
//添加then()方法 指定函数处理promise结果返回值
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState == 'fulfilled'){
onResolved(this.PromiseResult)
}
if (this.PromiseState == 'rejected'){
onRejected(this.PromiseResult)
}
if (this.PromiseState == 'pending'){//promise 状态为pending的时候执行
// 保存回调函数
this.callback.push({
onResolved:onResolved,
onRejected:onRejected
});
}
}