Promise基本实现
promise state状态的描述
A promise must be in one of three states: pending, fulfilled, or rejected.
1),When pending, a promise:may transition to either the fulfilled or rejected state.
2),When fulfilled, a promise:must not transition to any other state. must have a value, which must not change.
3),When rejected, a promise:must not transition to any other state.must have a reason, which must not change.
代码实现
const PENDING = 'pending';
const REJECTED = 'rejected';
const FULFILLED = 'fulfilled';
class Promise{
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status === FULFILLED) return;
this.value = value;
this.status = FULFILLED;
}
const reject = (reason) => {
if (this.status === REJECTED) return;
this.reason = reason;
this.status = REJECTED;
}
try {
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
}
promise then method
描述
- then返回的必须是一个Promise这样才能实现promise的链式调用
代码实现如下
then(onFulfilled, onRejected) {
const promise2 = new Promise1((resolve, reject)=>{
});
return promise2
}
- A promise’s then method accepts two arguments:
promise.then(onFulfilled, onRejected)
- then中的回调函数的返回值,决定了下一个then的行为:因此要特殊处理
- then中的参数为函数,then中回调函数的返回值,会传递个下一个then的回调函数中的形参。此时分两种情况
1,被then中失败函数捕获
上一个返回的是失败态的Promise或者抛出异常,会被下一个一个then中的失败所捕获
2,被then中成功函数捕获;// Promise失败状态 Promise.reject('1').then((v)=>{ console.log(v); //不走这里 }, (r)=>{ console.log(r); // 1 }) // 抛出异常错误 Promise.resolve('1').then(()=>{ return throw new Error('error') }).then(()=>{ }, (r)=>{ console.log(r); //会捕获到上一个then中抛出的错误 })
上一个返回的成功的promise或者说上一个的失败回调返回的是一个普通的值,会被下一个then的成功所捕获这里的普通值指的是非promise, 非错误,非异常
Promise.reject('1').then(()=>{ }, (r)=>{ return 'pre then error' }).then((v)=>{ console.log(v); //pre then error捕获上一个then失败函数中返回的普通值 })
- then中的参数为非函数,
因为then没有传递值或者说值不是函数,因此值向下传递,也就是常说的值的穿透问题
// 以下是原生Promise的行为 Promise.resolve('1').then().then().then((res)=>{ console.log(res); //1, })
- then中回调函数非返回值为Promise
// then中返回成功的promise Promise.resolve('1').then(v=>{ return new Promise((resolve,reject)=>{ resolve('ok') }) }).then((v)=>{ console.log(v); //ok }); //then中返回promise失败态 Promise.resolve('1').then(v=>{ return new Promise((resolve,reject)=>{ reject('reject') }) }).then((v)=>{ console.log(v, 'onFulfilled'); //不走这里 },(r)=>{ console.log(r, 'onRejected');//reject onRejected })
- then中的参数为函数,then中回调函数的返回值,会传递个下一个then的回调函数中的形参。此时分两种情况
then 方法的完整实现
then(onFulfilled, onRejected) {
const promise2 = new Promise1((resolve, reject) => {
// 处理参数为非函数的情况
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
// If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected with the same reason.
onRejected = typeof onRejected === 'function' ? onRejected : r => reject(r);
// 以下处理Promise状态异步改变的情况
// 需要then的回调函数暂存起来
// 需要对then函数的回调函数的返回值做处理 ,因为返回值有可能是Promise
// onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
// 因此这里需要异步来处理
if (this.status === PENDING) {
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
//
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
// const x = onRejected(this.reason); // 要求必须要在同意栈中调用
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
});
return promise2;
}
platform code的意思
Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
The Promise Resolution Procedure
- promise2 和x不能相等,如果相等就用TypeError作为reject的值返回
- 如果x 不是对象或者函数 直接resolve(x);
- 如果x是对象或者函数 如果let then = x.then
- 1、如果then为对象则resolve(x)
- 2、如果then为函数,x为then的this,y为then的value; r为then的reason,直接reject(r)返回失败的结果
注意 这里的y有可能还是Promise,因此需要对y进行resolvePromise处理;还需要注意的是,有可能内部调用promise改变promsie的状态,因此需要做冻结处理,次数再取then的地方加个开关
resolvePromise 方法的实现
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('不能循环引用'));
}
// x为对象或者函数
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
let called = false; //加开关防止then中的状态被篡改
try {
// x为函数
let then = x.then;
if (typeof then === 'function') {
then.call(x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject); //继续递归处理y
},
(r) => {
if (called) return;
called = true;
reject(r)
},
)
//x为对象
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
// x为普通值
}else {
resolve(x);
}
}
Promise基本代码的实现
const PENDING = 'pending';
const REJECTED = 'rejected';
const FULFILLED = 'fulfilled';
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('不能循环引用'));
}
// x为对象或者函数
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
let called = false;
try {
// x为函数
let then = x.then;
if (typeof then === 'function') {
then.call(x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return;
called = true;
reject(r)
},
)
//x为对象
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
// x为普通值
}else {
resolve(x);
}
}
class Promise1 {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === FULFILLED) return;
this.value = value;
this.status = FULFILLED;
this.onFulfilledCallbacks.forEach(fn => fn());
}
const reject = (reason) => {
if (this.status === REJECTED) return;
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn())
}
try {
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
const promise2 = new Promise1((resolve, reject) => {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => reject(r); // If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected with the same reason.
if (this.status === PENDING) {
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
});
return promise2;
}
}
Promise1.deferred = function () {
const dfd = {};
dfd.promise = new Promise1((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise1;
测试
用promises-aplus-tests这包来测试proise代码
下载包
npm install promises-aplus-tests -g
运行测试文件
promises-aplus-tests 文件名