Promise实现
这里超级安利大家去看《深入浅出nodejs》4.3.2 章节,别问我为啥老是安利这个,问就真的好看啊!!
Promise 规范
promise的规范有一大堆,但是es6采用了Promise A+ 规范
相信大家看完上面给的那个连接已经对整个promise的执行过程都有个了解了。 这里总结下
- 具有then方法,then()方法继续返回Promise对象,以实现链式调用。
- Promise操作只会处在3种状态的一种:未完成态(Pending)、完成态(Fulfilled)和失败态(Rejected)。
- Promise的状态只会出现从未完成态向完成态或失败态转化,不能逆反。完成态和失败态不能互相转化。
- Promise的状态一旦转化,将不能被更改。
- 接受完成态、错误态的回调方法。在操作完成或出现错误时,将会调用对应方法
实现
以下为菜狗子根据规范约定实(chao)现(xi),有错欢迎指出。
大佬们封装的promise实现测试工具,有实现完成的,可以用这个测试下是否符合标准。
大佬们封装好的例子想要看更多的,可以看这里。菜狗子的实现参考其中belofte.js为方便理解(就是懒)砍掉了许多类型判断。
const PENDING = "Pending";
const FULFILLED = "Fulfilled";
const REJECTED = "Rejected";
const root = typeof window === "undefined" ? global : window;
const isFunction = data => typeof data === "function";
const isMyPromise = fn => fn instanceof MyPromise;
const isObject = data =>
data && (typeof data === "object" || typeof data === "function");
// 因为promise是微任务,我们尽可能的去模拟
const nextTick = (function() {
if (typeof root.process === "object" && isFunction(root.process.nextTick)) {
// node环境
return function(fn) {
// process.nextTick 是微任务
root.process.nextTick(fn);
};
} else {
// 浏览器环境
return function(fn) {
// setTimeout 是宏任务
root.setTimeout(fn, 0);
};
}
})();
// 将promise由中间态到终态
const promiseResolutionProcedure = function(promise, result, async = true) {
if (promise === result) {
/**
* 因为promise 如果收到的value是一个promise会等待他的结果。
* 所以如果接受到的value是本身就递归了。
*
* @see https://promisesaplus.com/ 2.3.1 条规定
*/
promise._reject(new TypeError("Chaining cycle detected for promise"));
return;
}
// 如果接收到的是个promise
if (isMyPromise(result)) {
switch (result._state) {
case FULFILLED: {
nextTick(function() {
promise._resolve(result._value);
});
break;
}
case REJECTED: {
nextTick(function() {
promise._reject(result._reason);
});
break;
}
case PENDING: {
const _resolve = result._resolve;
const _reject = result._reject;
result._resolve = function(value) {
_resolve.call(result, value);
promise._resolve(value);
}.bind(result);
result._reject = function(reason) {
_reject.call(result, reason);
promise._reject(reason);
}.bind(result);
break;
}
}
return;
}
// 如果接受到的是个thenable 对象
if (isObject(result) && isFunction(result.then)) {
/**
* 多次调用只有第一次有效
*
* @see https://promisesaplus.com/ 2.3.3.3.3 条规定
*/
let flag = false;
const _resolve = function(value) {
if (flag) {
return;
}
flag = true;
promiseResolutionProcedure(promise, value);
};
const _reject = function(reason) {
if (flag) {
return;
}
flag = true;
promise._reject(reason);
};
const thenTemp = function() {
try {
result.then(_resolve, _reject);
} catch (error) {
_reject(error);
}
};
if (async) {
nextTick(thenTemp);
} else {
thenTemp();
}
return;
}
promise._resolve(result);
return;
};
class MyPromise {
constructor(resolver) {
if (!isFunction(resolver)) {
throw new TypeError("Promise resolver undefined is not a function");
}
/** @type { PENDING | FULFILLED | REJECTED} */
this._state = PENDING;
this._value = undefined;
this._reason = undefined;
this._isPromise = true;
/**
* 因为同一个promise可以被then 多次。
* 这里的多次不是指链式调用!!!!
* 这里理解了好久TAT
*/
this._resolveFnQueues = [];
this._rejectFnQueuse = [];
promiseResolutionProcedure(this, { then: resolver }, false);
}
_resolve(value) {
if (this._state !== PENDING) {
return;
}
this._state = FULFILLED;
this._value = value;
if (this._resolveFnQueues.length) {
nextTick(() => {
this._resolveFnQueues.forEach(cb => cb(value));
this._resolveFnQueues.length = 0;
this._rejectFnQueuse.length = 0;
});
}
}
_reject(reason) {
if (this._state !== PENDING) {
return;
}
this._state = FULFILLED;
this._reason = reason;
if (this._rejectFnQueuse.length) {
nextTick(() => {
this._rejectFnQueuse.forEach(cb => cb(reason));
this._resolveFnQueues.length = 0;
this._rejectFnQueuse.length = 0;
});
}
}
// then注册一个监听,在这个promise onFulfilled 或者 onRejected
then(onFulfilled, onRejected) {
onFulfilled = isFunction(onFulfilled) ? onFulfilled : MyPromise.resolve;
onRejected = isFunction(onRejected) ? onRejected : MyPromise.reject;
const chainPromise = new MyPromise(function() {});
const nextOnFulfilled = function(value) {
let result;
try {
result = onFulfilled(value);
promiseResolutionProcedure(chainPromise, result);
} catch (error) {
chainPromise._reject(error);
}
};
const nextOnRejected = function(reason) {
let result;
try {
result = onRejected(reason);
promiseResolutionProcedure(chainPromise, result);
} catch (error) {
chainPromise._reject(error);
}
};
switch (this._state) {
case FULFILLED: {
nextTick(() => {
nextOnFulfilled(this._value);
});
break;
}
case REJECTED: {
nextTick(() => {
nextOnRejected(this._reason);
});
break;
}
case PENDING: {
this._resolveFnQueues.push(nextOnFulfilled);
this._rejectFnQueuse.push(nextOnRejected);
}
}
return chainPromise;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
toString() {
switch (this._state) {
case PENDING:
return "Promise { <pending> }";
case FULFILLED:
return "Promise { " + this._value + " }";
case REJECTED:
return "Promise { <rejected> " + this._reason + " }";
}
}
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject() {
return new MyPromise((resolve, reject) => reject(value));
}
}
补充
async 实现
async 本质就是将 Generator 函数和自动执行器,包装在一个函数里
阮一峰大大的文章讲的炒鸡清楚了。这里的内容也来自于那篇文章,本人也就温习实现一下.
// async 的写法
async function fn(args){
// ...
}
// 等同于
function fn(args){
return spawn(function*() {
// ...
});
}
//spawn 的实现方式
function spawn(genF) {
return new Promise(function(resolve, reject) {
var gen = genF();
step(function() { return gen.next(undefined); });
function step(nextF) {
try {
var next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
});
}