Promise 库 lie.js 源码解读
web前端开发
共 9684字,需浏览 20分钟
·
2020-11-01 14:21
这篇文章是通过lie.js的源码一起去了解下如何实现Promise相关的规范。
首先是Promise的核心的构造函数的实现。
function INTERNAL() {}
var REJECTED = ['REJECTED'];
var FULFILLED = ['FULFILLED'];
var PENDING = ['PENDING'];
var handlers = {}
function Promise (resolver) {
if (typeof resolver !== 'function') {
throw new TypeError('resolver must be a function');
}
this.state = PENDING;
this.queue = [];
this.outcome = void 0;
/* istanbul ignore else */
if (!process.browser) {
this.handled = UNHANDLED;
}
if (resolver !== INTERNAL) {
safelyResolveThenable(this, resolver);
}
}
构造函数内部定义了几个promise实例的属性:
state:promise的状态值.有3种:rejected,fulfilled,pending
queue:queue数组用以保存这个promise被resolve/rejected后需要异步执行的回调
outcome:这个promise实例的值
对于promise,我们一般的用法是:
// 构造函数当中接收2个参数,resolve/reject,需要注意的是这2个参数是promise内部定义的,用以改变这个promise的状态和值
const promise = new Promise((resolve, reject) => {
// 同步或者异步的去resolve一个值
resolve(1)
})
给这个Promise构造函数内部传入的resolver由内部的方法safelyResolveThenable去执行:
function safelyResolveThenable(self, thenable) {
// Either fulfill, reject or reject with error
// 标志位,初始态的promise仅仅只能被resolve/reject一次
var called = false;
function onError(value) {
if (called) {
return;
}
called = true;
// reject这个promise
handlers.reject(self, value);
}
function onSuccess(value) {
if (called) {
return;
}
called = true;
// resolve这个promise
handlers.resolve(self, value);
}
// 用一个函数将resolver执行包裹一层
function tryToUnwrap() {
// 这个函数即由调用方传入的
thenable(onSuccess, onError);
}
// 用以捕获resolver在执行过程可能抛出的错误
var result = tryCatch(tryToUnwrap);
if (result.status === 'error') {
onError(result.value);
}
}
function tryCatch(func, value) {
var out = {};
try {
out.value = func(value);
out.status = 'success';
} catch (e) {
out.status = 'error';
out.value = e;
}
return out;
}
在safelyResolveThenable方法中设定了一个called标志位,这是因为一旦一个promise的状态发生了改变,那么之后的状态不能再次被改变,举例:
new Promise((resolve, reject) => {
// 一旦状态发生改变,后面的reject/resolve方法不能起作用
resolve(1)
reject(new Error('error'))
resolve(2)
})
如果给Promise构造函数传入callback在执行过程中没有报错,且被resolve的话,那么这个时候即调用的onSuccess方法,这个方法内部调用了handlers.resolve方法。
接下来我们看下这个方法的定义:
handlers.resolve = function (self, value) {
var result = tryCatch(getThen, value);
if (result.status === 'error') {
return handlers.reject(self, result.value);
}
// 判断这个value是否是个thenable对象
var thenable = result.value;
if (thenable) {
safelyResolveThenable(self, thenable);
} else {
// 将这个promise的state从 pending -> fulfilled
self.state = FULFILLED;
// 更改这个promise对应的值
self.outcome = value;
var i = -1;
var len = self.queue.length;
// 依次执行这个promise的queue队列里面每一项queueItem的callFulfilled方法
while (++i < len) {
self.queue[i].callFulfilled(value);
}
}
// 返回这个promise对象
return self;
}
再回到我们上面举的这个例子:
const promise = new Promise(resolve => {
resolve(1)
})
在这个例子当中,是同步去resolve这个promise,那么返回的这个promise实例的状态便为fulfilled,同时outcome的值也被设为1。
将这个例子拓展一下:
const promise = new Promise(resolve => {
resolve(1)
})
promise.then(function onFullfilled (value) {
console.log(value)
})
Promise.prototype.then = function (onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
typeof onRejected !== 'function' && this.state === REJECTED) {
return this;
}
// 创建一个新的promise
var promise = new this.constructor(INTERNAL);
/* istanbul ignore else */
if (!process.browser) {
if (this.handled === UNHANDLED) {
this.handled = null;
}
}
// new Promise在内部resolve过程中如果是同步的
if (this.state !== PENDING) {
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
unwrap(promise, resolver, this.outcome);
} else { // 异步的resolve
// this.queue保存了对于promise
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
}
return promise;
};
function unwrap(promise, func, value) {
// 异步执行这个func
immediate(function () {
var returnValue;
try {
// 捕获onFulfilled函数在执行过程中的错误
returnValue = func(value);
} catch (e) {
return handlers.reject(promise, e);
}
// 不能返回自身promise
if (returnValue === promise) {
handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
} else {
handlers.resolve(promise, returnValue);
}
});
}
function QueueItem(promise, onFulfilled, onRejected) {
// 首先保存这个promise
this.promise = promise;
// 如果onFulfilled是一个函数
if (typeof onFulfilled === 'function') {
this.onFulfilled = onFulfilled;
// 那么重新赋值callFulfilled函数
this.callFulfilled = this.otherCallFulfilled;
}
if (typeof onRejected === 'function') {
this.onRejected = onRejected;
this.callRejected = this.otherCallRejected;
}
}
// 如果onFulfilled是一个函数,那么就会覆盖callFulfilled方法
// 如果onFulfilled不是一个函数,那么就会直接调用handlers.resolve去递归处理promise
QueueItem.prototype.callFulfilled = function (value) {
handlers.resolve(this.promise, value);
};
QueueItem.prototype.otherCallFulfilled = function (value) {
unwrap(this.promise, this.onFulfilled, value);
};
QueueItem.prototype.callRejected = function (value) {
handlers.reject(this.promise, value);
};
QueueItem.prototype.otherCallRejected = function (value) {
unwrap(this.promise, this.onRejected, value);
};
onFullfilled:上一个promise被resolve后需要调用的回调
onRejected:上一个promise被reject后需要调用的回调函数
接下来我们看下第二种情况是在什么样的情况下去执行的:
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 3000)
})
promise.then(data => console.log(data))
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 2000)
})
promise
.then(3)
.then(console.log)
const promise = new Promise(resolve => {
// 情况一:同步resolve
resolve(1)
// 情况二:异步resolve
setTimeout(() => {
resolve(2)
}, 1000)
})
promise.then(function onFullfilled() {
// do something
foo()
})
bar()
const Promise = require('lie')
const promise = new Promise(resolve => setTimeout(resolve, 3000))
promise.then(() => 'a').then(() => 'b').then(() => {})
需要注意的是,在每个then方法内部创建的新的promise对象的state为pending态,outcome为null。可以将上面示例的promise打印到控制台,你会非常清晰的看到整个promise链的结构:
Promise {
state: [ 'PENDING' ],
queue:
[ QueueItem {
promise: {
state: ['PENDING'],
queue: [
QueueItem {
promise: {
state: ['PENDING'],
queue: [
QueueItem {
promise: {
state: ['PENDING'],
queue: [],
outcome: undefined
}
}
],
outcome: undefined,
handled: null
},
onFulfilled: [Function],
callFulfilled: [Function]
}
],
outcome: undefined,
handled: null
},
onFulfilled: [Function],
callFulfilled: [Function] } ],
outcome: undefined,
handled: null }
someRequest()
.then(res => {
if (res.error === 0) {
// do something
return res
} else {
return Promise.reject(res)
}
}).then(val => {
// do something
}).catch(err => {
// do something
})
评论