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