学习完event loop之后,对promise也有了新的认识,现在想自己写一个Promise的实现方式.
resolve的功能:
- 改变promise状态为onfulfilled
- 储存resolve(…)中的值
- 判断当前是否存在then(…)注册回调函数,如果存在则异步执行onRe
核心:
- 利用DOM Mutation 实现 microtask
步骤:
1 定义状态:一共四种
/**
* 0 -- pending
* 1 -- onfulfilled
* 2 -- rejected
* 3 -- adopt another promise as _value
*/
2 定义Promise类
一般都会在新建promise时传fn为参数. 实例变量包含
- state –> 表示Promise状态
- value –> 表示resolve的值
- defers –> 表示待执行的回调
原型方法有then,solve,reject,all,race(先实现then)
class Promise { constructor(fn) { if (typeof fn !== 'function') { throw new TypeError('Promise constructor\'s argument is not a function'); } this.state = 0; this.value = null this.defers = []; if( fn === noop ) return; doResolve(fn, this) } then(onFulfilled, onRejected) { let res = new Promise(noop); handle(this, new Handler(onFulfilled, onRejected, res)) return res; } }
3 定义Handler – 处理方法
包含三种属性
- onFulfilled
- onRejected
- promise
class Handler {
constructor(onFulfilled, onRejected, promise) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
this.promise = promise
}
}
4 定义doResolve,处理resolve和reject过程, 改变Promise状态
// use try--catch
function tryCallTwo(fn, a, b) {
try {
fn(a, b);
} catch (ex) {
GLOBAL_ERROR = ex;
return IS_ERROR;
}
}
function doResolve(fn, promise) {
let done = false;
let res = tryCallTwo(fn,
(value) => {
// guarantee resolve or reject only call once
if (done) return;
done = true;
resolve(promise, value)},
(reason) => {
if (done) return;
done = true;
reject(promise, reason)
});
// will not call any of resolve or reject
if(!done && res === IS_ERROR) {
done = true;
reject(promise, GLOBAL_ERROR)
}
}
请注意这里的if(done) return;
的作用,虽然只有一句话.请看下面的例子
let a = new Promise((res, rej) => {
res('resolved');
console.log('continue');
rej('reject');
})
a.then(res => console.log(res));
会打印continue, resolved 不会打印reject, 直接return掉了.
5 三个Promise的过程,resolve, reject, finale
/** use try-catch
* if some object has then method, it will be regarded as one promise
* such as let a = {then: resolve =>resolve(123)}
* let b = new Promise((resolve)=>resolve(a));
* b.then(v=>console.log(v)) // v = 123
*/
function getThen(obj) {
try {
return obj.then
} catch(ex) {
GLOBAL_ERROR = ex;
return IS_ERROR
}
}
function resolve(promise, newValue) {
// cannot be same one
if (newValue === promise) {
return reject(promise, new TypeError('a promise cannot resolve itself'))
}
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = getThen(newValue);
if (then === IS_ERROR) {
return reject(promise, GLOBAL_ERROR);
}
/**
* to handle resolve which is one Promise,such as
* let a = new Promise((res)=>res(111))
* let b = new Promise((res) => res(a))
* (then === promise.then is to judge same constructor)
*/
if(then === promise.then && newValue instanceof Promise) {
promise.state = 3;
promise.value = newValue;
finale(promise);
return;
}
// mimic promise: eg. let a = {then: (resolve, reject)=>resolve(123)}
else if (typeof then === 'function') {
doResolve(then.bind(newValue), promise);
return;
}
}
// change the state of promise
promise.state = 1;
// assign resolve(value) value to promise value
promise.value = newValue;
finale(promise)
}
function reject(promise, reason) {
promise.state = 2;
promise.value = reason;
finale(promise);
}
function finale(promise) {
let len = promise.defers.length
// handle the promise from defers
if (len > 0) {
for (let i = 0; i < len; i ++){
handle(promise, promise.defers[i])
}
promise.defers = null;
}
}
6 定义handle方法:用于处理回调
function handle(promise, defer) {
// if promise.value is a promise, the new resolved promise will assign to it until not promise anymore.
while (promise.state === 3) {
promise = promise.value
}
// for handle extend
if (Promise._onHandle){Promise._onHandle(promise)};
// if state is pending(not resolve at once)
if (promise.state === 0) {
// add defer including callback in defers queue
promise.defers.push(defer)
return;
}
// async call
handleResolve(promise, defer)
}
7 定义 handleResolve, 在此之前的代码全部都是同步的,只有这里才是异步,异步的实现为使用DOM Mutation,如果不支持,则使用setTimeout或setInterval
// use try--catch
function tryCallOne(fn, a) {
try {
return fn(a);
} catch (ex) {
GLOBAL_ERROR = ex;
return IS_ERROR;
}
}
function handleResolve(promise, defer) {
asap(function() {
let cb = promise.state === 1 ? defer.onFulfilled : defer.onRejected;
// if no callback in then method
if (cb === null) {
promise.state === 1 ? resolve(defer.promise, promise.value) : reject(defer.promise, promise.value);
return;
}
// if callback exists
let ret = tryCallOne(cb, promise.value);
ret === IS_ERROR ?
reject(defer.promise, GLOBAL_ERROR) :
resolve(defer.promise, ret)
})
}
Promise最大的用处便在于异步,异步过程实际上只在上述过程的handleResolve中.
resolve有两种情况
- 同步的resolve, 这种情况promise.defers里面不会有任何东西,then中的回调会立即被塞到异步队列中.
- 异步的resolve, 这种情况promise.defers会将then中的所有回调放到队列里,此时then中的回调并没有到异步队列中,只有当异步的resolve执行之后, 所有的回调再同步的被遍历,再被加到异步队列中.
注意then的链式调用:
每一次的promise resolve会检测是否有defer,如果有则将value传给defer中的onFulfilled,直到链中最后一个promise为止