目录
resolve与reject
我们看一段代码
let p1=new Promise((resolve,reject)=>{
resolve("成功")
reject("失败")
})
console.log('p1',p1);
let p2=new Promise((resolve,reject)=>{
reject('失败')
resolve('成功')
})
console.log('p2',p2);
let p3=new Promise((resolve,reject)=>{
throw('报错')
})
console.log('p3',p3);
在看结果:
从这里我们可以发现几个知识点:
- 执行resolve,Promise状态会变成fulfilled
- 执行reject,Promise状态会变成rejected
- Promise只以第一次为准,第一次成功就永久为
fulfilled
,第一次失败就永远状态为rejected - Promise中有throw的话,就相当于第一次执行reject
1.实现resolve与reject
大家要注意一下:Promise的初始状态是pending
这里很重要的一步是resolve和reject的绑定this
,为什么要绑定this
呢?这是为了resolve和reject的this指向
永远指向当前的MyPromise实例
,防止随着函数执行环境的改变而改变,我们接下来看代码:
class MyPromise{
// 创建构造方法
constructor(executor){
//初始化值
this.initValue()
// 初始化this指向
this.initBind()
// 执行传进来的函数
executor(this.resolve,this.reject)
}
initBind(){
// 初始化this
this.resolve=this.resolve.bind(this)
this.reject=this.reject.bind(this)
}
initValue(){
// 初始化值
this.PromiseResult=null; //终值
this.PromiseState='pedding' //状态
}
resolve(value){
// 如果执行resolve,状态为fulfilled
this.PromiseState='fulfilled'
// 终值为传进来的值
this.PromiseResult=value
}
reject(reason){
// 如果执行reject,状态变为rejected
this.PromiseState='rejected'
// 终值为传进来的reason
this.PromiseResult=reason
}
}
const t1=new MyPromise((resolve,reject)=>{
resolve('成功')
})
console.log(t1);
const t2=new MyPromise((resolve,reject)=>{
reject('失败')
})
console.log(t2);
这段代码传出的结果为:
t1:
t2:
2.状态不可变
上面说的由第一次状态决定状态其实是不正确的,如下:
const t3=new MyPromise((resolve,reject)=>{
resolve("成功")
reject("失败")
})
结果按我们的概念来说返回的应该为resolve('成功'),但结果为:
这是个什么原理呢?
因为Promise有三种状态:
- pending:等待中,是初始状态
- fulfilled:成功状态
- rejected:失败状态
一旦状态从pending变为fulfilled或者rejected时,那么Promise实例的状态就定死了
其实实现起来也很容易,在resolve与reject上加上判断条件即可:
resolve(value){
// 如果执行resolve,状态为fulfilled
// state是不可变的
if(this.PromiseState !== 'pending') return
this.PromiseState='fulfilled'
// 终值为传进来的值
this.PromiseResult=value
}
reject(reason){
// state是不可变的
if(this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState='rejected'
// 终值为传进来的reason
this.PromiseResult=reason
}
再来看看效果:
t3:
3.throw
Promise中有throw,就相当执行了reject,这个时候就可以使用try catch
// 创建构造方法
constructor(executor){
//初始化值
this.initValue()
// 初始化this指向
this.initBind()
try{
// 执行传进来的函数
executor(this.resolve,this.reject)
}catch(e){
// 有错误直接执行reject
this.reject(e)
}
}
const t4=new MyPromise((resolve,reject)=>{
throw("失败")
})
console.log(t4);
结果为:
then
then方法是Promise接收回调内容的
const p1=new Promise((resolve,reject)=>{
resolve("成功")
}).then(res=>console.log(res),err=>console.log(err))
// 马上输出成功
const p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("失败")
},1000)
}).then(res=>console.log(res),err=>console.log(err))
// 1秒后输出失败
const p3=new Promise((resolve,reject)=>{
resolve(100)
}).then(res => 2 * res ,err => console.log(err))
.then(res=>console.log(res),err=>console.log(err))
// 链式调用 输出200
可以总结几个知识点:
- then接收两个回调,一个是成功回调,一个是失败回调
- 当Promise状态为fulfilled执行成功回调,rejected执行失败回调
- 如resolve或rejected在定时器里,则定时器结束后再执行then
- then支持链式调用,下一次then执行受上一次then返回值的影响
1.实现then
then(onFulfilled,onRejected){
// /接收回调onFulfilled,onRejected
// 参数校验,确保为函数
onFulfilled=typeof onFulfilled === 'function' ? onFulfilled :val => val
onRejected=typeof onRejected === 'function' ? onRejected :reason => {throw reason}
if(this.PromiseState === 'fulfilled'){
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
}else if(this.PromiseState === 'rejected'){
// 如果当前为失败状态,执行第二个回调
onRejected(this.PromiseResult)
}
}
const test = new MyPromise((resolve, reject) => {
resolve('成功')
}).then(res => console.log(res), err => console.log(err))
// 输出 成功
2.定时器情况
上面我们已经基本实现了then的基本功能,那定时器呢
还是那个代码,怎么才能保证,1秒后才执行then里的失败回调呢?
这里的核心点在这1秒时间内,我们可以先把then里的两个回调保存起来,到1秒之后再执行resolve或者reject,最后再进行判断状态
initValue() {
// 初始化值
this.PromiseResult = null; //终值
this.PromiseState = 'pending' //状态
this.onFulfilledCallbacks = [] //保存成功回调
this.onRejectedCallbacks = []
}
resolve(value) {
// 如果执行resolve,状态为fulfilled
// state是不可变的
if (this.PromiseState !== 'pending') return
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
// 执行保存成功的回调
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult)
}
}
reject(reason) {
// state是不可变的
if (this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState = 'rejected'
// 终值为传进来的reason
this.PromiseResult = reason
// 执行保存失败的回调
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult)
}
}
then(onFulfilled, onRejected) {
// /接收回调onFulfilled,onRejected
// 参数校验,确保为函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二个回调
onRejected(this.PromiseResult)
} else if (this.PromiseState === 'pending') {
// 如果状态为等待,暂时保存两个回调
this.onFulfilledCallbacks.push(onFulfilled.bind(this))
this.onRejectedCallbacks.push(onRejected.bind(this))
}
}
我们看看执行结果:
const t2=new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("成功")
// reject("失败")
}, 1000)
}).then(res=>console.log(res),err=>console.log(err))
3.链式调用
then支持链式调用
,下一次then执行受上一次then返回值的影响
,给大家举个例子:
const t3 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => 2 * res, err => console.log(err))
.then(res => console.log(res), err => console.log(err))
const t4=new Promise((resolve,reject)=>{
resolve(100)
}).then(res=>new Promise((resolve,reject)=>resolve(3 * res)),err => console.log(err)).then(res=> console.log(res),err=> console.log(err))
结果为200,300
从什么的内容我们可以获取几个知识点
- then方法本身会返回一个新的Promise对象
- 如果返回值是promise对象,返回值为成功,新promise就是成功
- 如果返回值是promise对象,返回值为失败,新promise就是失败
- 如果返回值为非promise对象,新promise对象就是成功,值为此返回值
咱们知道then是Promise上的方法,那如何实现then完还能再then呢?很简单,then执行后返回一个Promise对象
就行了,就能保证then完还能继续执行then,代码实现:
then(onFulfilled, onRejected) {
// /接收回调onFulfilled,onRejected
// 参数校验,确保为函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
var thenPromise=new MyPromise((resolve,reject)=>{
const resolvePromise=cb =>{
try{
const x =cb(this.PromiseResult)
if(x === thenPromise){
// 不能返回自身
throw new Error('不能返回自身。。。')
}
if(x instanceof MyPromise){
// 如果返回值是Promise
x.then(resolve,reject)
}else{
// 非Promise就直接成功
resolve(x)
}
}catch(err){
// 处理报错
reject(err)
throw new Error(er)
}
}
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
resolvePromise(onFulfilled)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二个回调
onRejected(this.PromiseResult)
resolvePromise(onRejected)
} else if (this.PromiseState === 'pending') {
// 如果状态为等待,暂时保存两个回调
this.onFulfilledCallbacks.push(onFulfilled.bind(this))
this.onRejectedCallbacks.push(onRejected.bind(this))
this.onFulfilledCallbacks.push(resolvePromise.bind(this,onFulfilled))
this.onRejectedCallbacks,push(resolvePromise.bind(this,onRejected))
}
})
// 返回这个包装的Promise
return thenPromise
}
调用代码:
const t3 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => 2 * res, err => console.log(err))
.then(res => console.log('成功', res), err => console.log('失败', err))
const t4=new Promise((resolve,reject)=>{
resolve(100)
}).then(res => new Promise((resolve, reject) => reject(2 * res)), err => new Promise((resolve, reject) => resolve(3 * err))).then(res=> console.log('成功',res),err=> console.log('失败',err))
结果为:
4.微任务
看过js执行机制
的兄弟都知道,then方法是微任务
,啥叫微任务呢?其实不知道也不要紧,我通过下面例子让你知道:
const t=new Promise((resolve,reject)=>{
resolve(1)
}).then(res=>console.log(res),err=>console.log(err))
console.log(2);
输出顺序为2,1
为啥不是 1 2 呢?因为then是个微任务啊。。。同样,我们也要给我们的MyPromise加上这个特性(我这里使用定时器,大家别介意哈)
只需要让resolvePromise函数
异步执行就可以了
const resolvePromise = cb => {
setTimeout(() => {
try {
const x = cb(this.PromiseResult)
if (x === thenPromise) {
// 不能返回自身
throw new Error('不能返回自身。。。')
}
if (x instanceof MyPromise) {
// 如果返回值是Promise
x.then(resolve, reject)
} else {
// 非Promise就直接成功
resolve(x)
}
} catch (err) {
// 处理报错
reject(err)
throw new Error(er)
}
})
}
效果为:
const t=new MyPromise((resolve,reject)=>{
resolve(1)
}).then(res=>console.log(res),err=>console.log(err))
console.log(2);
//顺序为2 1
Promise还有着其他的方法,我就不细谈了哈