手写promise源码介绍
1、promise的resolve reject then函数实现
1.1、promise有3种状态
const STATUS = {
PENDING: 'PENDING', // 等待中
FUFILLED: 'FUFILLED', // 成功
REJECTED: 'REJECTED' // 失败
};
1.2、promise使用的时候需要new Promise()
let p = new Promise((resolve, reject) => {
setTimeout(() => {
// reject('失败了');
resolve('成功了');
}, 1000);
// throw new Error('错误了');
});
// 订阅起来
p.then(
(data) => {
console.log('success', data);
},
(reason) => {
console.log('fail', reason);
}
);
1.3 由上可知 promise是一个构造函数,参数是一个函数,并且形参是resolve, reject,并且有then方法(then接受2个函数,成功和失败)
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
},
then(onFulfilled, onRejected) {
}
}
1.4 处理创建promise时的状态, resolve()后会改变status
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
// 存放成功回调 (订阅列表)
this.onResolvedCallbacks = [];
// 存放失败回调
this.onRejectedCallbacks = [];
const resolve = (val) => {
// 是promise 就继续递归执行
if (val instanceof Promise) {
return val.then(resolve, reject);
}
// 改变为成功状态并执行then里面的成功回调
if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// resolve时就调用列表 (发布执行)
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
// 改变为失败状态并执行then里面的失败回调
const reject = (reason) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
1.5 then函数链式调用
// promise链式调用
// 1. 如果then方法中 返回不是一个promise,
// 会将这个值传递给外层下次then的成功结果
// 2. 如果执行then方法中的方法出错了 抛出异常 走到下一个then的失败中
// 3. 如果返回的是一个promise, 结果会作为下一次then的成功或者失败
function read(...args) {
return new Promise((resolve, reject) => {
fs.readFile(...args, function (err, data) {
if (err) return reject(err);
resolve(data);
});
});
}
// 1.出错会失败 2.返回的promise会出错
// catch 就是then的别名 没有成功只有失败(找最近的有限处理,处理不了的找下一层)
// then方法为什么可以链式调用, 每次调用then都是返回一个新的promise
read(resolvePath('name.txt'), 'utf8')
.then(
(data) => {
throw new Error('error了');
// return 100;
},
(err) => {
console.log('1then err', err);
// throw new Error(err);
}
)
.then(
(data) => {
console.log('2then', data);
}
// (err) => {
// console.log('2then err', err);
// }
)
.then(null, (err) => {
console.log('catch', err);
return 2;
})
.then((data) => {
console.log('last then', data);
});
1.6 链式调用说明一个then函数之后,会返回个新的promise对象,它才有then方法
then返回promise
假设x是一个正常值,resolve一个值就ok 新返回的promise就可以触发then里面的成功回调了
class Promise {
...
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// 同步处理
if (this.status === STATUS.FUFILLED) {
try {
let x = onFulfilled(this.value);
resolve(x)
} catch (error) {
reject(error);
}
}
if (this.status === STATUS.REJECTED) {
try {
let x = onRejected(this.reason);
resolve(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}
// 异步处理
if (this.status === STATUS.PENDING) {
// 装饰模式 切片编程
this.onResolvedCallbacks.push(() => {
try {
// todo...
let x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
});
this.onRejectedCallbacks.push(() => {
try {
// todo...
let x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
});
}
});
return promise2;
}
}
1.7 假如then的onFulfilled函数return一个新的promise 要如何处理呢 如下图
// 判断返回值和promise的关系
let promise2 = p1.then(
(data) => {
return new Promise((resolve, reject) => {
resolve('999');
});
},
(err) => {
return 200;
}
);
promise2.then(
(data) => {
console.log('promise2', data); // 999
},
(err) => {
console.log('err', err);
}
);
// 或者嵌套promise 递归处理
let promise2 = new Promise((resolve, reject) => {
let p = new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('999');
}, 1000);
})
);
})
);
});
let a = Promise.resolve(p);
console.log('a', a);
p.then((data) => {
// 999
console.log(data);
});
resolve(p);
});
promise2.then((data) => {
// 999
console.log(data);
});
如何实现呢
看下面
增加一个resolvePromise函数
resolvePromise解析x是不是promise或者普通值,resolve该值就能传给下一个promise2的then函数里面
如果是嵌套promise, 就递归处理 直到拿到普通值 再resolve
// 防止x是一个特殊对象 就报错了
// Object.defineProperties('x', 'then' {
// get() {
// if(time == 2) {
// throw new Error();
// }
// }
// })
// 看x是普通值还是promise 如果是promise采用他的状态
function resolvePromise(x, promise2, resolve, reject) {
// 防止自己等待自己完成
if (promise2 == x) {
return reject(new TypeError('出错了'));
}
// 看x是普通值还是promise 如果是promise 要采用他的状态
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
// x可以是一个对象或者函数
let called; // 标志位 防止resolve reject同时进行
try {
// 34行
let then = x.then;
// 看这个对象是否有then方法
if (typeof then == 'function') {
// 有then函数 我就认为x是一个promise
// 如果x是promise 那么就采用他的状态
// 类似这个语法
// x.then(() => {
//
// }, err => {
//
// })
// 复用32行就好了 防止有报错可能性 14行介绍了
then.call(
x,
function (y) {
// 调用返回的promise 用他的结果 作为下一次then的结果。
if (called) return;
called = true;
// y就是成功的值 999 或者y是一个promise 要用递归思路
// 递归解析成功后的值 直到他是一个普通值为止
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x); // 此时x 就是一个普通对象
}
} catch (error) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x); // x不是promise 是一个原始数据
}
// 不是promise 直接调用resolve
}
class Promise {
...
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// 同步处理
if (this.status === STATUS.FUFILLED) {
// 创建一个宏任务 为了拿到promise2 (promise2还没new完拿不了的)
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === STATUS.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 异步处理
if (this.status === STATUS.PENDING) {
// 装饰模式 切片编程
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
// todo...
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
// todo...
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
}
1.8 then函数为什么能够等待resolve(x)后执行呢?
1.8.1 如果是同步任务 then之前其实就resolve或者reject了,status状态改变了
then函数直接进去后就是FUFILLED或者REJECTED状态,就可以执行resolvePromise了。
1.8.2 如果是异步任务,then进去后还是pending状态, 故把执行的onFulfilled放进去onResolvedCallbacks队列或者onRejected函数放进去onRejectedCallbacks队列,
等resolve时状态改变后再执行队列 函数
try catch 是为了捕捉onFulfilled函数的错误
const resolve = (val) => {
// 是promise 就继续递归执行
if (val instanceof Promise) {
return val.then(resolve, reject);
}
if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// resolve时就调用列表 (发布执行)
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
1.9 如果then是空函数,怎么透传呢
例如下面用法
const p = new Promise((resolve, reject) => {
resolve('ok');
});
// 功能1-- p.then空传参也可以resolve的值透传下去
p.then()
.then()
.then((data) => {
console.log(data); // ok
});
如果then是空函数,那就自动补充onfullfilled后者onrejected函数吧
then(onFulfilled, onRejected) {
// 没传onFulfilled 就设置默认函数 就可以默认拿到then里面的data了
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (data) => data;
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err;
};
...
2、catch函数实现
其实catch就是then的换种写法,
代码如下
catch(err) {
// 默认直走失败 没有成功 then的简单写法 err是函数
return this.then(null, err);
}
3、Promise.resolve如何实现呢
下面的使用 Promise.resolve返回新的promise2
let pp = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 1000);
});
// Promise.resolve可以等待一个promise执行完毕
Promise.resolve(pp).then((data) => {
console.log(data);
});
本质就是一个静态方法
static resolve(val) {
return new Promise((resolve, reject) => {
resolve(val);
});
}
注意:如果pp是一个promise就会等待pp里面的resolve()之后再处理, val.then函数参数resolve函数会拿到222,参数resolve是外层的resolve, 改变了外层promise的状态 就能后续then了
const resolve = (val) => {
// 是promise 就继续递归执行
if (val instanceof Promise) {
return val.then(resolve, reject);
}
if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// resolve时就调用列表 (发布执行)
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
4、Promise.defer实现
static defer() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
使用时减少new Promise使用 代码更省略
function read(...args) {
//defer减少了 new Promise 套用 应该是模仿$.defer()等
let dfd = Promise.defer();
fs.readFile(...args, function (err, data) {
if (err) return dfd.reject(err);
dfd.resolve(data);
});
return dfd.promise;
}
let p1 = read(resolvePath('name.txt'), 'utf8');
let promise2 = p1.then(
(data) => {
return data;
},
(err) => {
return 200;
}
);
5、 Promise.all()方法实现
使用如下
promise.all会等待全部promise resolve后 执行then
let fs = require('fs').promises;
let getName = fs.readFile(resolvePath('./name.txt'), 'utf8');
let getAge = fs.readFile(resolvePath('./age.txt'), 'utf8');
// Promise.all方法返回一个promise
Promise.all([1, getName, getAge, 2]).then((data) => {
console.log(data);
});
实现如下
本质返回一个promise
记录每个promise的执行结果, 如果是promise 就用promise.then去获取resolve后的值 再记录如result数组,times 记录次数 等到全部执行完毕就resolve(result)
static all(promises) {
// 判断是不是promise
function isPromise(val) {
return typeof val.then == 'function';
}
return new Promise((resolve, reject) => {
let result = [];
let times = 0;
function processData(index, val) {
result[index] = val;
// 每次加1做处理次数 等于传入的promises数组长度时 就完成了 resolve就行了
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (isPromise(p)) {
p.then((data) => {
processData(i, data); // 普通值
}, reject); // reject处理后 返回的promise就可以catch了
} else {
processData(i, p); // 普通值
}
}
});
};
6、 finally()方法实现
finally无论如何都会执行 data会是undefined
使用方法
Promise.reject(123)
.finally((data) => {
// 不管成功还是失败 都执行
// 这里传入的函数 无论如何都会执行
console.log('finally', data); //undefined
// finally可以返回一个promise
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok'); // Promise.reject(123) resolve会跑下面的失败, 但是用123的值 reject会跑到下面的err 用ok
}, 2000);
});
})
.then(
(data) => {
console.log('suc:', data);
return 2;
},
(err) => {
console.log('err:', err);
}
);
源码分析:
finally(callback) {
return this.then(
(data) => {
console.log('then data', data);
// 让函数执行内部会调用方法 如果方法是promise需求等待她完成
return Promise.resolve(callback()).then((res) => {
return data;
});
},
(err) => {
// reject
return Promise.resolve(callback()).then(() => {
throw err;
});
}
);
}
最后附一份完整手写的源码
总结:
其实Promise本质是一个构造函数, 里面实现了各种方法 then catch finally等。
为了达到链式调用目的, 每个方法其实都是返回一个新的promise对象, 那么该对象就能链式继续调用then了, 至于控制异步status状态变化, 其实就是把then里面onfullfilled先挂起到队列, 等resolve后就再调用队列的函数,达到了回调的效果。
/*
* @description:
* @author: steve.deng
* @Date: 2020-10-14 18:12:38
* @LastEditors: steve.deng
* @LastEditTime: 2020-10-26 16:48:31
*/
const STATUS = {
PENDING: 'PENDING',
FUFILLED: 'FUFILLED',
REJECTED: 'REJECTED'
};
// 防止x是一个特殊对象 就报错了
// Object.defineProperties('x', 'then' {
// get() {
// if(time == 2) {
// throw new Error();
// }
// }
// })
// 看x是普通值还是promise 如果是promise采用他的状态
function resolvePromise(x, promise2, resolve, reject) {
// 防止自己等待自己完成
if (promise2 == x) {
return reject(new TypeError('出错了'));
}
// 看x是普通值还是promise 如果是promise 要采用他的状态
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
// x可以是一个对象或者函数
let called; // 标志位 防止resolve reject同时进行
try {
let then = x.then;
// 看这个对象是否有then方法
if (typeof then == 'function') {
// 有then函数 我就认为x是一个promise
// 如果x是promise 那么就采用他的状态
// 类似这个语法
// x.then(() => {
//
// }, err => {
//
// })
// 复用32行就好了 防止有报错可能性 14行介绍了
then.call(
x,
function (y) {
// 调用返回的promise 用他的结果 作为下一次then的结果。
if (called) return;
called = true;
// y就是成功的值 999 或者y是一个promise 要用递归思路
// 递归解析成功后的值 直到他是一个普通值为止
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x); // 此时x 就是一个普通对象
}
} catch (error) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x); // x不是promise 是一个原始数据
}
// 不是promise 直接调用resolve
}
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
// 存放成功回调 (订阅列表)
this.onResolvedCallbacks = [];
// 存放失败回调
this.onRejectedCallbacks = [];
const resolve = (val) => {
// 是promise 就继续递归执行
if (val instanceof Promise) {
return val.then(resolve, reject);
}
if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// resolve时就调用列表 (发布执行)
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
// 没传onFulfilled 就设置默认函数 就可以默认拿到then里面的data了
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (data) => data;
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err;
};
let promise2 = new Promise((resolve, reject) => {
// 同步处理
if (this.status === STATUS.FUFILLED) {
// 创建一个宏任务 为了拿到promise2 (promise2还没new完拿不了的)
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === STATUS.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 异步处理
if (this.status === STATUS.PENDING) {
// 装饰模式 切片编程
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
// todo...
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
// todo...
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
catch(err) {
// 默认直走失败 没有成功 then的简单写法 err是函数
return this.then(null, err);
}
finally(callback) {
return this.then(
(data) => {
console.log('then data', data);
// 让函数执行内部会调用方法 如果方法是promise需求等待她完成
return Promise.resolve(callback()).then((res) => {
return data;
});
},
(err) => {
// reject
return Promise.resolve(callback()).then(() => {
throw err;
});
}
);
}
static resolve(val) {
return new Promise((resolve, reject) => {
resolve(val);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static defer() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
static all(promises) {
function isPromise(val) {
return typeof val.then == 'function';
}
return new Promise((resolve, reject) => {
let result = [];
let times = 0;
function processData(index, val) {
result[index] = val;
// 每次加1做处理次数 等于传入的promises数组长度时 就完成了 resolve就行了
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (isPromise(p)) {
p.then((data) => {
processData(i, data); // 普通值
}, reject); // reject处理后 返回的promise就可以catch了
} else {
processData(i, p); // 普通值
}
}
});
}
}
// 测试时会调用这个方法
// Promise.defer = Promise.deferred = function () {
// let dfd = {};
// dfd.promise = new Promise((resolve, reject) => {
// dfd.resolve = resolve;
// dfd.reject = reject;
// });
// return dfd;
// };
// 安装测试工具包
// npm install promises-aplus-tests -g
module.exports = Promise;