Promise 库 lie.js 源码解读

这篇文章是通过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这个promisehandlers.reject(self, value);}function onSuccess(value) {if (called) {return;}called = true;// resolve这个promisehandlers.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 -> fulfilledself.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;}// 创建一个新的promisevar 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保存了对于promisethis.queue.push(new QueueItem(promise, onFulfilled, onRejected));}return promise;};
function unwrap(promise, func, value) {// 异步执行这个funcimmediate(function () {var returnValue;try {// 捕获onFulfilled函数在执行过程中的错误returnValue = func(value);} catch (e) {return handlers.reject(promise, e);}// 不能返回自身promiseif (returnValue === promise) {handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));} else {handlers.resolve(promise, returnValue);}});}
function QueueItem(promise, onFulfilled, onRejected) {// 首先保存这个promisethis.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去递归处理promiseQueueItem.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 => {// 情况一:同步resolveresolve(1)// 情况二:异步resolvesetTimeout(() => {resolve(2)}, 1000)})promise.then(function onFullfilled() {// do somethingfoo()})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 somethingreturn res} else {return Promise.reject(res)}}).then(val => {// do something}).catch(err => {// do something})

评论
