简易版 promise 实现步骤
- 确定状态
- 实现 .then 调用和异步执行
- 实现 new Promise 内的异步逻辑
- 实现 .then 的链式调用
确定状态
promise 的状态是不可改变的,根据这一特性创建构造函数。 promise 函数接收一个 executor 函数,executor 函数执行完同步或异步操作后,调用它的参数 resolve 或 reject
class Promise2 {
static PENDING = 'pending'
static RESOLVED = 'resolved'
static REJECTED = 'rejected'
constructor(executor) {
this.status = Promise2.PENDING
this.value = ''
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.RESOLVED
this.value = val
}
}
reject(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.REJECTED
this.value = val
}
}
}
const p1 = new Promise2((resolve, reject)=>{
resolve(1)
})
console.log(p1); // { status: 'resolved', value: 1 }
实现 .then 调用和异步执行
then 接收两个参数,onResolved onRejected 分别为成功和失败的回调
class Promise2 {
// ... 代码省略
then(onResolved, onRejected) {
// 根据标准,then 的参数需要是函数
if (typeof onResolved !== 'function') {
onResolved = value => value
}
if (typeof onRejected !== 'function') {
onRejected = value => value
}
if(this.status == Promise2.RESOLVED) {
try {
onResolved(this.value)
} catch (error) {
onRejected(error)
}
}
if(this.status == Promise2.REJECTED) {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
}
}
}
const p1 = new Promise2((resolve, reject) => {
resolve(1)
}).then(res => {
console.log('res',res);
}, err => {
console.log('err',err);
})
在看一个案例
const p1 = new Promise2((resolve, reject) => {
resolve(1)
}).then(res => {
console.log('res',res);
}, err => {
console.log('err',err);
})
console.log('同步');
// 此时先打印 res 1, 后打印 同步
Promise 的机制是 then 回调函数必须异步执行。为什么?因为这样保障了代码执行顺序的一致性。 所以应该先打印 同步 后打印 res 1
if(this.status == Promise2.RESOLVED) {
setTimeout(() => {
try {
onResolved(this.value)
} catch (error) {
onRejected(error)
}
});
}
if(this.status == Promise2.REJECTED) {
setTimeout(() => {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
});
}
实现 new Promise 内的异步逻辑
const p1 = new Promise2((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 500);
})
console.log(p1); // { status: 'pending', value: '' }
通过上面测试案例可以,此时的 status 是 pending。所以我们在 .then 里在添加一个 status == 'pending' 的判断。
同时再添加一个 callbacks 属性,用于保存 .then(...) 里的函数。
那么什么时候执行 callbacks(.then(...)) 里的函数呢?
答案是我们把 callbacks 放在 resolve() 和 reject() 方法里。当 setTimeout 时间到了,执行 resolve(1) 的时候。
class Promise2 {
static PENDING = 'pending'
static RESOLVED = 'resolved'
static REJECTED = 'rejected'
constructor(executor) {
this.status = Promise2.PENDING
this.value = ''
this.callbacks = [] // 新增
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.RESOLVED
this.value = val
// 新增
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].onResolved(this.value)
}
}
}
reject(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.REJECTED
this.value = val
// 新增
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].onRejected(this.value)
}
}
}
then(onResolved, onRejected) {
// 根据标准,then 的参数需要是函数
if (typeof onResolved !== 'function') {
onResolved = value => value
}
if (typeof onRejected !== 'function') {
onRejected = value => value
}
// 新增
if (this.status == Promise2.PENDING) {
this.callbacks.push({
onResolved: (value) => {
try {
onResolved(this.value)
} catch (error) {
onRejected(error)
}
},
onRejected: (value) => {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
}
})
}
if (this.status == Promise2.RESOLVED) {
setTimeout(() => {
try {
onResolved(this.value)
} catch (error) {
onRejected(error)
}
});
}
if (this.status == Promise2.REJECTED) {
setTimeout(() => {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
});
}
}
}
const p1 = new Promise2((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 500);
}).then(res => {
console.log('res', res); // res 1
})
实现 .then 的链式调用
只需要再 then 方法里 return new Promise2 即可。
这里需要执行 onResolved(value) 后获取 返回值res,并调用 resolve(res)。
class Promise2 {
static PENDING = 'pending'
static RESOLVED = 'resolved'
static REJECTED = 'rejected'
constructor(executor) {
this.status = Promise2.PENDING
this.value = ''
this.callbacks = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.RESOLVED
this.value = val
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].onResolved(this.value)
}
}
}
reject(val) {
if (this.status == Promise2.PENDING) {
this.status = Promise2.REJECTED
this.value = val
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].onRejected(this.value)
}
}
}
then(onResolved, onRejected) {
// 根据标准,then 的参数需要是函数
if (typeof onResolved !== 'function') {
onResolved = value => value
}
if (typeof onRejected !== 'function') {
onRejected = value => value
}
// 新增
return new Promise2((resolve, reject) => {
if (this.status == Promise2.PENDING) {
this.callbacks.push({
onResolved: (value) => {
try {
const res = onResolved(value)
resolve(res)
} catch (error) {
const res = onRejected(error)
reject(res)
}
},
onRejected: (value) => {
try {
const res = onRejected(value)
reject(res)
} catch (error) {
const res = onRejected(error)
reject(res)
}
}
})
}
if (this.status == Promise2.RESOLVED) {
setTimeout(() => {
try {
const res = onResolved(this.value)
resolve(res)
} catch (error) {
const res = onRejected(error)
reject(res)
}
});
}
if (this.status == Promise2.REJECTED) {
setTimeout(() => {
try {
const res = onRejected(this.value)
reject(res)
} catch (error) {
const res = onRejected(error)
reject(res)
}
});
}
})
}
}
const p1 = new Promise2((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 500);
}).then(res => {
console.log('res', res);
return 2
}).then(res => {
console.log('res2', res);
return 3
})
Promise then中回调为什么是异步执行?
Promise 的机制就是 then 回调函数必须异步执行。为什么?因为这样保障了代码执行顺序的一致性。
先看一个场景:
promise.then(function(){
if (trueOrFalse) {
// 同步执行
foo();
} else {
// 异步执行 (如:使用第三方库)
setTimeout(function(){
foo();
})
}
});
bar();
- 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行?
答案是,如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。
在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。 - 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行?
答案一目了然,bar() 先执行,foo() 后执行。
所以为了保证代码执行顺序的一致性, then 回调必须保证是异步的。