基础用法:
let p = new Promise((resolve, reject) => {
resolve('success')
})
console.log(p);
p.then(value => {
console.log(value);
})
- promse是一个类
- 接收一个函数
executor
,而且这个它会立即执行 executor
内部调用resolve(value)
或reject(reason)
会把值传递到then
方法(为啥这里叫方法不叫函数呢?)的回调里面,他们一定共享了value和reason在一个地方,是绑到全局还是this上呢- 要是在全局的话,多次
new Promise
呢?
class Promise {
constructor(executor) {
this.value = undefined
this.reason = undefined
executor(this.resolve.bind(this), this.reject.bind(this))
}
resolve(value) {
this.value = value
}
reject(reason) {
this.reason = reason
}
then(onFulfilled, onRejected) {
onFulfilled(this.value)
// or
onRejected(this.reason)
}
}
module.exports = Promise
onFulfilled
和onRejected
到底执行哪个,是不是需要给个标识呢- 这个标识存在哪里,在哪里变化呢,
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
resolve('success')
reject('error')
})
console.log(p);
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
- 根据promiseA+规范
- 标识只能由
PENGDING
->FULFILLED
或PENGDING
->REJECTED
,需加flag excutor错误需要触发reject ```javascript const PENDING = ‘PENDING’ const FULFILLED = ‘FULFILLED’ const REJECTED = ‘REJECTED’ class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.bind(this, error)
} }
resolve(value) { if (this.status === PENDING) {
this.status = FULFILLED this.value = value
} }
reject(reason) { if (this.status === PENDING) {
this.status = REJECTED this.reason = reason
} }
then(onFulfilled, onRejected) { if (this.status === FULFILLED) {
onFulfilled(this.value)
} if (this.status === REJECTED) {
onRejected(this.reason)
} }
}
module.exports = Promise
回调:
- 到目前为止,像点样子了,
- 把耗时的工作放到了executor里面,then里面注册回调,当耗时的工作(目前只支持同步的,为啥)做完了,会调用then,同时执行then里面注册的回调(这里的回调只是在then里面,**excutor里拿不到**),所以必须excutor执行完了再执行then,不然回调就丢了。
- 🌚,这就导致了它现在还不支持异步
```javascript
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
console.log(p);
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
// Promise { status: 'PENDING', value: undefined, reason: undefined }
- 那么要想让他支持异步怎么办呢?
- 在excutor异步回调里,再去执行我们在then里注册的回调,这就需要这个回调能访问到,很容易我就可以想到:把它也放到this上呀。
- 从上面我们可以看到,then里的两个回调都没执行,理由是,这是状态还在PENDING;
所以这种状态下,我们需要把回调存起来 ```javascript const PENDING = ‘PENDING’ const FULFILLED = ‘FULFILLED’ const REJECTED = ‘REJECTED’ class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined this.onFulfilledCb = null this.onRejectedCb = null try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.bind(this, error)
} }
resolve(value) { if (this.status === PENDING) {
this.status = FULFILLED this.value = value this.onFulfilledCb(this.value)
} }
reject(reason) { if (this.status === PENDING) {
this.status = REJECTED this.reason = reason this.onRejectedCb(this.reason)
} }
then(onFulfilled, onRejected) { if (this.status === FULFILLED) {
onFulfilled(this.value)
} if (this.status === REJECTED) {
onRejected(this.reason)
} if (this.status === PENDING) {
this.onFulfilledCb = onFulfilled this.onRejectedCb = onRejected
} }
}
module.exports = Promise
ok,先看起来是不是完美了?<br />其实,promise还有很多骚操作呢。<br />比如下方:
```javascript
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
console.log(p);
p.then(value => {
console.log(value);
}, reason => {
console.log('sdf', reason);
})
// 多次在同一个promise上执行then方法呢?注意,这里不是链式调用
p.then(value=>{
console.log(value);
})
// 期望打印两次
// 实际只打印了一次
再一次改造:
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCbs = []
this.onRejectedCbs = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.bind(this, error)
}
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onFulfilledCbs.forEach(fn=>fn(this.value))
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCbs.forEach(fn => fn(this.value))
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if (this.status === PENDING) {
this.onFulfilledCbs.push(()=>{
// 在这里传值是不是很奇怪呀
onFulfilled(this.value)
})
this.onRejectedCbs.push(()=>{
onRejected(this.reason)
})
}
}
}
module.exports = Promise
改造后,达到我们的预期了。
那么,接着来的链式调用呢:
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 100)
})
p.then(value => {
console.log(value);
return 100
}, reason => {
console.log(reason);
}).then(value => {
console.log(value)
})
看起来又捉襟见肘了,如何支持链式调用呢?
// 会不会如下呢,then里返回this
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if (this.status === PENDING) {
this.onFulfilledCbs.push((value)=>{
onFulfilled(value)
})
this.onRejectedCbs.push((reason)=>{
onRejected(reason)
})
}
return this
}
确实不报错了, 但也不符合我们的预期,根据推测,第一次then之后应该,返回的是一个新的promise,我们暂且叫它promise2
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCbs = []
this.onRejectedCbs = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.bind(this, error)
}
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onFulfilledCbs.forEach(fn => fn(this.value))
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCbs.forEach(fn => fn(this.value))
}
}
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// repeat
try {
let x = onFulfilled(this.value)
resolve(x)
} catch (error) {
reject(error)
}
}
if (this.status === REJECTED) {
// repeat
try {
let x = onRejected(this.reason)
resolve(x)
} catch (error) {
reject(error)
}
}
if (this.status === PENDING) {
this.onFulfilledCbs.push((value) => {
// 我们把值传递过来啦
// repeat
try {
let x = onFulfilled(value)
resolve(x)
} catch (error) {
reject(error)
}
})
this.onRejectedCbs.push((reason) => {
// repeat
try {
let x = onRejected(reason)
resolve(x)
} catch (error) {
reject(error)
}
})
}
})
return promise2
}
}
module.exports = Promise
这样确实实现了链式调用,我确实有一些疑问,为什么48行明明rejected了,却还要调resolve,将值流转的promise2的then的onFulfilled里面,为什么catch的error要调reject,将值流转到promise2的then的onRejected里面。
这些其实是promiseA+规范里定的:除了抛错或promise,其他都是普通值,会流转到下一个then到onFulfilled里面。
Wait,抛错和普通值我们知道了,promise是什么鬼?
const Promise = require('./promise');
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(time)
}, time)
})
}
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(100)
}, 100)
})
p.then(value => {
return sleep(value)
}, reason => {
console.log(reason);
}).then(value => {
console.log(value)
})
我们判断下return的x是什么值
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
const resovePromise = (x, promise2, resolve, reject) => {
if (x === promise2) {
return reject(new TypeError())
}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
let then = x.then
// thenable
if (typeof then === 'function') {
then.call(x, (y) => {
resolve(y)
}, (r) => {
reject(r)
})
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
} else {
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCbs = []
this.onRejectedCbs = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject.bind(this, error)
}
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED-
this.value = value
this.onFulfilledCbs.forEach(fn => fn(this.value))
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCbs.forEach(fn => fn(this.value))
}
}
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resovePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
console.log(promise2);
let x = onRejected(this.reason)
resovePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
}
if (this.status === PENDING) {
this.onFulfilledCbs.push((value) => {
// 我们把值传递过来啦
setTimeout(() => {
try {
let x = onFulfilled(value)
resovePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
this.onRejectedCbs.push((reason) => {
setTimeout(() => {
try {
let x = onRejected(reason)
resovePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
}
})
return promise2
}
}
module.exports = Promise