手写Promise
1.最简实现Promise(20行)
作者:晨曦时梦见兮
这是一个成功回调
function Promise(excutor) {
this.callbacks = [];
function resolve(value) {
setTimeout(() => {
this.data = value;
this.callbacks.forEach((callback) => callback(value));
});
}
excutor(resolve.bind(this));
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.callbacks.push(() => {
const result = onResolved(self.data);
if (result instanceof Promise) {
result.then(resolve);
} else {
resolve(result);
}
});
});
};
如何实现
先实现Promise的构造函数。promise对象中,有回调队列[],resolve(),以及一个执行器excutor
function Promise(excutor) {
var self = this;
self.onResolvedCallback = [];
function resolve(value) {
setTimeout(() => { //制造异步函数
self.data = value;
self.onResolvedCallback.forEach((callback) => callback(value));//执行回调队列
});
}
// 执行用户传入的函数
excutor(resolve.bind(self));
}
有了构造函数,还需要一个then()方法就能实现链式调用了。
- then()方法返回的是一个promise对象
- 能获取到异步执行的结果
Promise.prototype.then = function (onResolved) {
// 保存上下文,哪个promise调用的then,就指向哪个promise。
var self = this;
// 一定要返回一个新的promise
return new Promise((resolve) => {
self.onResolvedCallback.push(function () {
var result = onResolved(self.data);
if (result instanceof Promise) {
// promise 用户会自己在定时器等异步逻辑里面去resolve
// 此时这个then方法会被触发 新promise才被resolve 新promise的callbacks里的方法被执行
// 注意新promise的callbacks并不是self.onResolvedCallback 而是新promise自身的 onResolvedCallback
result.then(resolve);
} else {
resolve(result);
}
});
});
};
可以看到then方法,先拿到了调用then对象的上下文,然后又将新的promise对象的OnResolved(),放入自己的回调队列中。等待上一个promise执行完异步操作,来执行这个回调队列。
这样又把新promise的OnResolved()给执行了,也就是说新的promise的状态是由上一个promise决定的。这样就形成了链式的样子。
2.完善Promise
Promise的阉割模型
(function(window){
//Promise构造函数
//executor 执行器函数,同步执行
function Promise(executor){
function resolve (value){}
function reject(reason){}
executor(resolve,reject)
}
//Promise原型对象上的then()
//这个函数指定成功和失败的回调
//返回一个新的promise对象
Promise.prototype.then = function(onResolved,onRejected){
}
//原型对象上的catch方法
//指定失败的回调
//返回新的promise
Promise.prototype.catch = function(onRejected){
}
//接下来是函数对象的方法 与原型对象上的方法有所不同 函数上的方法(通过动态赋值给构造函数的方法)不继承 ,也就是说实例对象上没有,不能调用
//函数对象的resolve方法
//返回一个指定结果的成功的promise
Promise.resolve = function(value){
}
//函数对象上的reject方法
Promise.reject = function(reason){
}
//函数对象上的all方法
//返回一个promise 都成功才成功 有一个失败就全失败
Promise.all = function(promises){ //promises是一个数组,里面装的是promise对象
}
//函数对象上的race方法
//返回一个promise对象 其结果由第一个完成的promise来决定
Promise.race = function(promises){
}
window.Promise = Promise
})(window)
Promise构造函数
function Promise(executor){
//三种状态
const PENDING ="pending"
const RESOLVED = "resolved"
const REJECTED = "rejected"
// 将promise对象保存起来
const self = this
self.status = 'PENDING' //给promise指定初始状态值 初始值为PENDING 等待态
self.data = undefined //给promise指定一个储存结果数据的属性
self.callbacks = [] //一个回调序列 存储已经指定的回调 结构为包含两个回调函数的对象{onResolved(){},onRejected(){}}
function resolve (value){
//只有是初始状态PENDING才能改变状态 所以要加一层判断
if(self.status !== "PENDING"){
return
}
//将状态改为RESOLVED
self.status = RESOLVED
//保存value数据
self.data = value
//如果有还未执行的call回调函数,立即异步执行回调函数onResolved 去回调序列里边找
//由于需要异步执行 这里使用一下setTimeOut将这个回调函数放入宏队列里去
if(self.callbacks.length > 1){
setTimeout(() =>{ //放入宏队列,执行所有成功回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
});
})
}
}
function reject(reason){
//只有是初始状态PENDING才能改变状态 所以要加一层判断
if(self.status !== "PENDING"){
return
}
//将状态改为REJECTED
self.status = REJECTED
//保存reason数据
self.data = reason
//如果有还未执行的call回调函数,立即异步执行回调函数onRejected 去回调序列里边找
//由于需要异步执行 这里使用一下setTimeOut将这个回调函数放入宏队列里去
if(self.callbacks.length > 1){
setTimeout(() =>{ //放入宏队列,执行所有成功回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
});
})
}
}
//立即同步执行executor
try { //如果执行器抛出异常,也就是说既不会执行成功回调也不会执行失败回调
executor(resolve,reject) //所以这里要去捕获一下异常 如果抛出异常,promise对象变为REJECTED状态
} catch (error) {
reject(error) //执行reject() 使promise失败
}
}
then()方法
then(onResolved,onRejected) {
//return一个新的promise
return new MyPromise((resolve, reject) => {
//把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
const onResolved = value => {
try {
//执行第一个(当前的)Promise的成功回调,并获取返回值
let x = onResolved(value)
//分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
//这里resolve之后,就能被下一个.then()的回调获取到返回值,从而实现链式调用
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
//把后续then收集的依赖都push进当前Promise的成功回调队列中(_rejectQueue), 这是为了保证顺序调用
this.callbacks.push(onResolved)
//reject同理
const onRejected = error => {
try {
let x = onRejected(error)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
this._rejectQueue.push(onRejected)
})
}