共计 4816 个字符,预计需要花费 13 分钟才能阅读完成。
promsie 使用及原理 / 手写一个符合 promise/A+ 规范的 promise
promise 使用及原理分析:
- 通过 new 关键字创建 promise 实例, 接受一个 executor 参数, executor 方法返回两个方法 resolve, reject, 可用通过在 executor 方法中通过调用 resolve(使成功) 或调用 reject(使失败), 来控制 promise 状态
let p = new Promise((resolve, reject) => {resolve(100)
})
- executor 中可以执行同步代码也可以执行异步代码
let p = new Promise((resolve, reject) => {setTimeout(() => {resolve(100)
})
})
- promise 原型对象上有 then 方法供 promise 实例调用, then 方法接受两个参数 onFulfilled, onRejected
- onFulfilled 默认为一个函数 data => data
- onRejected 默认为一个函数 err => {throw err}
- 当 promise 状态为 fulfilled 时, 执行用户传入的 onFulfilled 方法
- 当 promise 状态为 rejected 时, 执行用户传入的 onRected 方法
- 当用户创建 promise 对象时采用异步, 那么执行 then 方法时没有调用 resolve 方法或 reject 方法, 所以 promise 状态依然为 pending 状态, 所以需要在 then 方法中采取发布订阅模式, 先保存 then 方法传来的 onFulfilled 和 onReje
- 又因为同一个 promise 实例可以调用多次 then 方法, 从而传多个 onFulfilled 和 onRected, 所以发布订阅采用数组保存
- onFulfilled 和 onRejected 方法中可能 throw Error, 所以在执行 onFulfilled 和 onRejected 时需要 try catch 捕获
- then 方法返回一个新的 Promise 实现链式编程
- 统一判断 then 方法传入的 onFulfilled 方法和 onRejected 方法中 return 的类型 (resolvePromise)
p.then(data => {console.log(data)
}, err => {console.log(err)
})
let p1 = p.then(data => {return p1 // 报类型错误})
p.then(data => {return new Promise((resolve, reject) => {resolve(100)
})
})
- catch 方法接受一个错误回调, 可以用 then 方法实现 (语法糖)
- ES2018 中新增 finally 方法 也可以通过 then 方法实现 (语法糖) finally 要实现值得穿透, finally 前如果有 then 方法, 其返回值要穿过 finally 方法传给之后的 then
p.then(data => {return 100}).finally(() => {console.log('finally')
}).then(data => {console.log(data) // 100
})
- all, race 方法都接受一个 promise 数组
- all 方法要所有 promise 都返回才 resolve 一个全部是成功态的数组, 只要有一个 rejected 就直接 reject
- race 方法只要有一个 promise resolve 就直接 resolve
完整代码如下:
class Promise {constructor(executor) {
this.status = Promise.PENDING
this.value = undefined
this.reason = undefined
// 发布订阅的存储器 onResolvedCallbacks, onRejectedCallbacks
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
this.initBind()
this.init(executor)
}
initBind() {this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
init(executor) {
// 防止 executor 中抛错
try {executor(this.resolve, this.reject)
} catch (e) {this.reject(e)
}
}
resolve(data) {
// 如果 resolve 中传入一个 promise, 那么返回改 promise 结果
if (data instanceof Promise) data.then(this.resolve, this.reject)
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED
this.value = data
this.onResolvedCallbacks.forEach(fn => fn())
}
}
reject(reason) {if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
then(onFulfilled, onRejected) {const fulfilledHandle = (resolve, reject) => {
// 此处用 setTimeout 异步才能拿到 promise2
setTimeout(() => {
try {let x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {reject(e)
}
})
}
const rejectHandle = (resolve, reject) => {setTimeout(() => {
try {let x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {reject(e)
}
})
}
// onFulfilled 和 onRejected 定义默认值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
let promise2 = new Promise((resolve, reject) => {if (this.status === Promise.FULFILLED) {fulfilledHandle(resolve, reject)
}
if (this.status === Promise.REJECTED) {rejectHandle(resolve, reject)
}
if (this.status === Promise.PENDING) {this.onResolvedCallbacks.push(() => {fulfilledHandle(resolve, reject)
})
this.onRejectedCallbacks.push(() => {rejectHandle(resolve, reject)
})
}
})
// 返回一个新的 promise
return promise2
}
catch (onRejected) {return this.then(null, onRejected)
}
static resolve() {return new Promise((resolve, reject) => {resolve()
})
}
static reject() {return new Promise((resolve, reject) => {reject()
})
}
finally(callback) {
return this.then(data => Promise.resolve(callback()).then(() => data),
err => Promise.resolve(callback()).then(() => {throw err})
)
}
static all(promises) {return new Promise((resolve, reject) => {let result = []
let count = 0
const setResult = (key, value) => {result[key] = value
if (++count === promises.length) {resolve(result)
}
}
for (let i = 0; i < promises.length; i++) {let current = promises[i]
if (Promise.isPromise(current)) {
current.then(data => {setResult(i, data)
}, reject)
} else {setResult(i, current)
}
}
})
}
static race(promises) {return new Promise((resolve, reject) => {for (let i = 0; i < promises.length; i++) {let current = promises[i]
if (Promise.isPromise(current)) {current.then(resolve, reject)
} else {resolve(current)
}
}
})
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = (promise2, x, resolve, reject) => {
// called 防止他人的 promise 即执行 resolve 又执行 reject
let called
if (promise2 === x) throw new TypeError('xxx')
if (typeof x === 'function' || typeof x === 'object' && x !== null) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {if (called) return
called = true
// 递归解析, 总有一个结果 then 方法返回一个普通值
Promise.resolvePromise(promise2, y, resolve, reject)
}, e => {if (called) return
called = true
reject(e)
})
} else {resolve(x)
}
} catch (e) {if (called) return
called = true
reject(e)
}
} else {resolve(x)
}
}
Promise.isPromise = (obj) => {return typeof obj === 'function' || typeof obj === 'object' && obj !== null && obj.then && typeof obj.then === 'function'}
// 延迟对象
Promise.deferred = () => {const defer = {}
defer.promise = new Promise((resolve, reject) => {
defer.resolve = resolve
defer.reject = reject
})
return defer
}
module.exports = Promise
正文完
发表至: javascript
2019-06-17