promise的代码遵循以下几点
1.promise状态的不可变性,只能由pending到fulfilled,或者pending到rejected;
2.promise支持异步,采用setTimeout;
3.promise中采用.then的链式调用,原理是返回新的promise,而不是返回自身。
Promises/A+规范
then方法里做了两件事,1.把前面resolve的值传到回调函数中;2.把当前then方法中的返回值,传递到下一个then方法里
class myPromise {
constructor(exc) {
this.success = null
this.fail = null
this.state = "pending"
this.resolveArr = []
this.rejectArr = []
let resolve = (value) => {
if (this.state == "pending") {
this.state = "fulfilled"
this.success = value
//增加resolve时遍历执行
this.resolveArr.forEach(fn => fn())
}
}
let reject = (value) => {
if (this.state == "pending") {
this.state = "rejected"
//增加reject时遍历执行
this.fail = value
this.rejectArr.forEach(fn => fn())
}
}
try {
exc(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// 判断是否为函数,不是函数转为函数的格式
onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (value) => value
onRejected = typeof onRejected == "function" ? onRejected : (err) => { throw err }
let promise2 = new myPromise((resolve, reject) => {
if (this.state == "fulfilled") {
setTimeout(() => {
try {
const x = onFulfilled(this.success)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error);
}
}, 0)
}
if (this.state == "rejected") {
setTimeout(() => {
try {
const x = onRejected(this.fail)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error);
}
}, 0)
}
//增加pending判断
if (this.state == "pending") {
this.resolveArr.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.success)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error);
}
}, 0)
})
this.rejectArr.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.fail)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error);
}
}, 0);
})
}
})
return promise2
}
catch(fn) {
this.then(null, fn)
}
}
x值可能出现以下几种类型:普通值,对象,函数,promise。因为promise的类型属于object,所以只需要判断3种类型:普通值,对象,函数。如果可以执行.then方法说明返回值是个promise,那么就可以拿到promise中resolve的值,接着继续判断值类型,依次类推,递归执行此方法。
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 == x) {
// throw ("不能循环引用自己")
reject(new TypeError("Chaining cycle detected for promise"));
}
// 防止多次调用
let called;
if ((typeof x == "object" && x !== null) || typeof x === 'function') {
// promise实例x, x类型为object, x.then类型为function
try {
// 这边直接使用then的话,下面要改变this指向
let then = x.then
if (typeof then === "function") {
then.call(x,
(res) => {
if (called) return;
called = true;
//如果内部还是promise,则递归调用
resolvePromise(promise2, res, resolve, reject)
},
err => {
if (called) return;
called = true;
// 直接抛异常,不再深层次判断
reject(err)
// resolvePromise(promise2, err, resolve, reject)
})
} else {
// 对于x类型为function
if (called) return;
called = true;
resolve(x);
}
} catch (err) {
if (called) return;
called = true;
reject(err)
}
} else {
// 对于普通值
if (called) return;
called = true;
resolve(x)
}
}
附赠resolve,reject方法
myPromise.resolve = (val) => {
return new myPromise((resolve, reject) => {
// 相当于执行constructor中的resolve方法
resolve(val);
});
};
myPromise.reject = (val) => {
return new myPromise((resolve, reject) => {
reject(val);
});
};
此处不直接使用resolve而使用myPromise.resolve,是因为resolve后状态就改变了,整个myPromise.all就结束了
myPromise.all = (promises) => {
return new myPromise((resolve, reject) => {
let count = 0;
const result = [];
for (let i = 0; i < promises.length; i++) {
// 此处不直接使用resolve而使用myPromise.resolve是因为,resolve后状态就改变了,整个myPromise.all就结束了
const promise = myPromise.resolve(promises[i]).then(res => res)
promise.then((res) => {
result.push(res);
count++;
if (count === promises.length) {
resolve(result);
}
})
.catch((err) => {
reject(err);
});
}
});
};
测试自己写的对不对?
myPromise.deferred = function () {
const defer = {}
defer.promise = new myPromise((resolve, reject) => {
defer.resolve = resolve
defer.reject = reject
})
return defer
}
module.exports = myPromise
运行命令
npm i promises-aplus-tests -g
npx promises-aplus-tests promise.js
1.为何promise要resolve()之后才能.then?
此处的resolve指的是constructor中的resolve方法,当resolve执行完之后,状态就会由pending转为fulfilled。当状态为fulfilled,then方法对应的方法才会继续执行,所以then方法的执行是通过判断状态的改变。
2.then方法中的回调函数为何能取到reolve的值?
onFulfilled(this.success)
会通过回调函数把值传出来,同时也会resolve当前函数的返回值,传递给下一个.then方法中,当不是普通值时会进一步深层次判断,但最终都要resolve,所以想要传递下去必须要resolve。
3.对于值穿透的理解?
值穿透会发生在then方法参数不是一个函数,那么就会把它转为一个函数,暴露的都是传入的参数,所以才会发生值穿透,若不想值穿透,传入函数即可。因为如果是回调函数,则暴露相应的返回值。