前言
手写promise的学习笔记,纯粹图一乐,方便后续的复习啥的,如果有错误或者更好的方法,希望看到的大佬不吝赐教
步骤
1 了解promise规范,上一篇笔记已经更新 promiseA+规范(英文)
2 实现
3 测试 promiseA+测试工具
这一篇着重实现,顺带测试一下,部分规范在代码中也会附带的说明一下
开始
构造函数
statusMap = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected",
};
class Promise {
constructor(fn) {
this.status = statusMap.PENDING;
this.value = undefined;
this.reason = undefined;
//new Promise的时候,需要传入一个方法,方法包含两个参数,用来根据执行结果改变promise的状态和value或者reason
fn(
(value) => {
//因为测试用例中有一个套娃的例子,value是thenable,所以这里走promise解析的方法
//fulfilledPromise(this,value)
resolvePromise(this, value);
},
(reason) => {
rejectedPromise(this, reason);
}
);
}
then() {}
}
改变promise状态的方法
由于状态只能从pending改变成其他状态,所以只能状态只能改变一次,所以方法中做了判断
function fulfilledPromise(promise, value) {
if (promise.status !== statusMap.PENDING) return;
promise.status = statusMap.FULFILLED;
promise.value = value;
}
function rejectedPromise(promise, reason) {
if (promise.status !== statusMap.PENDING) return;
promise.status = statusMap.REJECTED;
promise.reson = reason;
}
//promise 解析过程,由于会分好几种情况,最后再写
function resolvePromise(promise, x) {
// todo
}
//后面要用到的公共方法
function isFunction(fn) {
return (
Object.prototype.toString.call(fn).toLocaleLowerCase() ===
"[object function]"
);
}
function isPromise(x) {
return x instanceof Promise
}
function isObject(obj) {
return (
Object.prototype.toString.call(obj).toLocaleLowerCase() ===
"[object object]"
);
}
then
...部分代码省略...
function runCbs(list, value) {
list.forEach((cb) => cb(value));
}
function fulfilledPromise(promise, value) {
if (promise.status !== statusMap.PENDING) return;
promise.status = statusMap.FULFILLED;
promise.value = value;
//改变状态时执行then里面的回调
runCbs(promise.fulfilledCbs, value);
}
function rejectedPromise(promise, reason) {
if (promise.status !== statusMap.PENDING) return;
promise.status = statusMap.REJECTED;
promise.reason = reason;
runCbs(promise.rejectedCbs, reason);
}
class Promise {
constructor(fn) {
this.status = statusMap.PENDING;
this.value = undefined;
this.reason = undefined;
this.fulfilledCbs = []; //promise可以多次调用then方法,所以用数组储存then里面的fulfilled回调函数
this.rejectedCbs = [];
fn(
(value) => {
resolvePromise(this, value);
},
(reason) => {
rejectedPromise(this, reason);
}
);
}
then(onFulfilled, onRejected) {
let promise1 = this;
let promise2 = new Promise(() => {});
if (promise1.status === statusMap.FULFILLED) {
//如果onFulfilled不是一个函数,则忽略
if (!isFunction(onFulfilled)) {
return promise1;
}
//then 里面的方法施异步执行,用setTimeout模拟异步
setTimeout(() => {
try {
//onRejected或者onFulfilled return了一个值X,则进入解析过程
let x = onFulfilled(promise1.value);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
});
}
if (promise1.status === statusMap.REJECTED) {
//如果onFulfilled不是一个函数,则忽略
if (!isFunction(onRejected)) {
return promise1;
}
setTimeout(() => {
try {
let x = onRejected(promise1.reason);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
});
}
//promsie的status为pending 的时候,需要等待new Promsie 时传入的参数出结果
//然后通过传给then的回调获取结果
if (promise1.status === statusMap.PENDING) {
onFulfilled = isFunction(onFulfilled) ?
onFulfilled :
(value) => {
return value;
};
onRejected = isFunction(onRejected) ?
onRejected :
(error) => {
throw error;
};
//
//promise可以多次调用then,onfulfilled和onRejected会根据promsie状态改变的时候视情况按照注册顺序执行
promise1.fulfilledCbs.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(promise1.value);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
});
});
promise1.rejectedCbs.push(() => {
setTimeout(() => {
try {
let x = onRejected(promise1.reason);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
});
});
}
return promise2;
}
}
promise解析
promis解析有四种情况
- 1 如果promise和x指向同一个值
- 2 如果x是一个promise
- 3 如果x是一个对象或者函数
- 4 如果x既不是一个对象也不是函数
function resolvePromise(promise, x) {
//如果promise和x指向同一个值
if (promise === x) {
rejectedPromise(promise, new TypeError('cant be same'))
return
}
//如果x是一个promise
if (isPromise(x)) {
//如果x的状态是fulfilled,则将x的value 作为promise的value,将他的状态改为fulfilled
if (x.status === statusMap.FULFILLED) {
fulfilledPromise(promise, x.value)
return
}
if (x.status === statusMap.REJECTED) {
rejectedPromise(promise, x.reason)
return
}
if (x.status === statusMap.PENDING) {
x.then(
() => {
fulfilledPromise(promise, x.value)
},
() => {
rejectedPromise(promise, x.reason)
}
)
return
}
return
}
if (isObject(x) || isFunction(x)) {
//thenable
let then
let isCall = false
try {
then = x.then
} catch (error) {
rejectedPromise(promise, error)
return
}
if (isFunction(then)) {
try {
then.call(x,
(y) => {
if (isCall) return
isCall = true
resolvePromise(promise, y)
},
(r) => {
if (isCall) return
isCall = true
rejectedPromise(promise, r)
}
)
} catch (error) {
if (isCall) return
isCall = true
rejectedPromise(promise, error)
}
return
} else {
fulfilledPromise(promise, x)
return
}
} else {
fulfilledPromise(promise, x)
return
}
}
完整代码
statusMap = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected",
};
//将promise设置为fulfilled状态
function fulfilledPromise(promise, value) {
//promise的状态只能改变一次,只能从pending改变为其他状态
if (promise.status !== statusMap.PENDING) {
return;
}
promise.status = statusMap.FULFILLED;
promise.value = value;
//改变状态时会异步执行then里面的回调
runCbs(promise.fulfilledCbs, value);
}
//将promise设置为rejected状态
function rejectedPromise(promise, reason) {
//promise的状态只能改变一次
if (promise.status !== statusMap.PENDING) {
return;
}
promise.status = statusMap.REJECTED;
promise.reason = reason;
//改变状态时会异步执行then里面的回调
runCbs(promise.rejectedCbs, reason);
}
function isFunction(fn) {
return (
Object.prototype.toString.call(fn).toLocaleLowerCase() ===
"[object function]"
);
}
function isPromise(p) {
return p instanceof Promise;
}
function isObject(obj) {
return (
Object.prototype.toString.call(obj).toLocaleLowerCase() ===
"[object object]"
);
}
function runCbs(cbs, val) {
cbs.forEach((cb) => cb(val));
}
//promise 解析过程
function resolvePromise(promise, x) {
//如果promise和x指向同一个值
if (x === promise) {
rejectedPromise(promise, new TypeError("cant be the same"));
return;
}
//如果x是一个promise
if (isPromise(x)) {
if (x.status === statusMap.FULFILLED) {
fulfilledPromise(promise, x.value);
return;
}
if (x.status === statusMap.REJECTED) {
rejectedPromise(promise, x.reason);
return;
}
if (x.status === statusMap.PENDING) {
x.then(
() => {
fulfilledPromise(promise, x.value);
},
() => {
rejectedPromise(promise, x.reason);
}
);
return;
}
return;
}
//如果x是一个对象或者函数(thenable)
if (isObject(x) || isFunction(x)) {
let then;
let isCalled = false;
try {
then = x.then;
} catch (error) {
rejectedPromise(promise, error);
return;
}
//如果then是一个函数
if (isFunction(then)) {
try {
then.call(
x,
(y) => {
if (isCalled) return;
isCalled = true;
resolvePromise(promise, y);
},
(r) => {
if (isCalled) return;
isCalled = true;
rejectedPromise(promise, r);
}
);
} catch (error) {
//如果执行过程出错,则需要看一下两个函数是否已经执行过了,
//如果执行过了,说明promise的状态已经改变过了,所以按照规范不能再次改变,所以不错处理
//如果没有执行过,需要把promise设置为rejected状态,他的reason是执行时返回的异常
if (isCalled) {
return;
}
isCalled = true;
rejectedPromise(promise, error);
}
return;
} else {
//如果then不是一个函数,则将x作为promise的值,将promise状态变成fulfilled
fulfilledPromise(promise, x);
return;
}
} else {
//如果x不是对象也不是函数,则将x作为promise的值,将promise状态变成fulfilled
fulfilledPromise(promise, x);
return;
}
}
class Promise {
constructor(fn) {
this.status = statusMap.PENDING;
this.value = undefined;
this.reason = undefined;
this.fulfilledCbs = []; //promise可以多次调用then方法,所以用数组储存then里面的fulfilled回调函数
this.rejectedCbs = [];
//创建promise的时候,会传入一个函数,函数有用两个方法resolve和reject作为参数
// let p= new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log("执行");
// resolve("then执行");
// }, 2000);
// });
fn(
(value) => {
resolvePromise(this, value);
},
(reason) => {
rejectedPromise(this, reason);
}
);
}
//要有一个then方法
then(onFulfilled, onRejected) {
const promise1 = this;
//then方法会return一个promise
const promise2 = new Promise(() => {});
if (promise1.status === statusMap.FULFILLED) {
if (!isFunction(onFulfilled)) {
return promise1;
}
setTimeout(() => {
try {
const x = onFulfilled(promise1.value);
//x的值会影响到新生成的promise2
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
}, 0);
}
if (promise1.status === statusMap.REJECTED) {
if (!isFunction(onRejected)) {
return promise1;
}
setTimeout(() => {
try {
const x = onRejected(promise1.reason);
//x的值会影响到新生成的promise2
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
}, 0);
}
//如果是pending状态则需要等到promise的参数(回调函数)执行出结果
//执行出来的结果则需要通过传给then的参数(回调函数)取得
if (promise1.status === statusMap.PENDING) {
onFulfilled = isFunction(onFulfilled) ?
onFulfilled :
(value) => {
return value;
};
onRejected = isFunction(onRejected) ?
onRejected :
(err) => {
throw err;
};
promise1.fulfilledCbs.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(promise1.value);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
}, 0);
});
promise1.rejectedCbs.push(() => {
setTimeout(() => {
try {
const x = onRejected(promise1.reason);
resolvePromise(promise2, x);
} catch (error) {
rejectedPromise(promise2, error);
}
}, 0);
});
}
return promise2;
}
}
Promise.deferred = function() {
const deferred = {};
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
};
module.exports = Promise;