深耕系列之promise原理

·  阅读 481

一、问题引入

不知你是否有以下疑问:

  1. Promise是什么来的?
  2. Promise是为了解决什么问题而引入进来的?
  3. 在没有Promise前,我们是如何写代码的?
  4. Promise是如何使用的?
  5. Promise在事件循环中的执行过程是怎么样的?
  6. 为什么promise在浏览器和node宿主环境上执行有差异?
  7. 如何手写一个Promise?
  8. Promise和async/await有什么关联?

如果这些问题你还有一丢丢困惑,那么欢迎继续往下看.

二、Promise出现缘由

众所周知的是,Javascript一个既有同步操作又有异步操作的语言,异步操作包含setTimeout,ajax等,而业务需求中经常会有通过ajax去请求后端数据的场景。

如果有多次ajax请求时,代码的结构是怎么样的呢?

首先,我们先用setTimeout来模拟一次ajax异步请求

function ajax(cb) {
	setTimeout(function() {
		cb('返回')
	}, 1000)
}
复制代码

那么在多次ajax请求场景下,代码结构会变成:

ajax(function(msg1) {
    ajax(function(msg2) {
		ajax(function(msg3) {
			ajax(function(msg4) {
				ajax(function(msg4) {
					
				})
			})
		})
	})
})
复制代码

显而易见的是,这样的代码结构可读性差,可维护性差,只能在回调里处理异常,大家也把这种代码结构称为回调地狱

那么为了解决这个问题,ES6把Promise纳入了规范中,作为一种异步编程的解决方案,比传统的回调函数事件监听观察者模式等解决方案要更合理。

参考 异步解决方案

三、什么是Promise

Promise到底是如何解决异步编程问题的,怎么使用的,我们继续往下看:

Promise代码结构

我们先来看一下Promise的代码结构

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(1000).then((value) => {
  console.log(value);
	return timeout(2000);
}).then((value) => {
  console.log(value);
	return timeout(3000);
}).then((value) => {
  console.log(value);
});
复制代码

从代码来看,Promise可通过then链式调用来处理多个异步请求,成功则触发resolve函数,失败则触发reject函数。 而仅仅这些还不够,Promise还需要处理函数报错,不能改变状态等,所以就有了Promises/A+规范。

Promises/A+规范

  1. Promise 存在三个状态(state)pending、fulfilled、rejected
  2. pending(等待态)为初始态,并可以转化为fulfilled(成功态)和rejected(失败态)
  3. 成功时,不可转为其他状态,且必须有一个不可改变的值(value)
  4. 失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
  5. new Promise((resolve, reject)=>{resolve(value)}) resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。
  6. new Promise((resolve, reject)=>{reject(reason)}) reject为失败,接收参数reason,状态改变为rejected,不可再次改变。
  7. 若是executor函数报错 直接执行reject();

这只是其中一部分,更多可参考 promises/A+规范

Promise的API

API解释
Promise.prototype.then()状态改变时的回调函数
Promise.prototype.catch()用于指定发生错误时的回调函数
Promise.prototype.finally()最终都会执行的回调函数
Promise.prototype.all()用于执行多个Promise实例(所有操作状态变更相同才更改状态)
Promise.prototype.race()用于执行多个Promise实例(有一个操作状态变更就更改状态)
Promise.prototype.allSettled()用于执行多个Promise实例(所有操作状态都变更才更改状态)

更多可参考 promise介绍

四、Promise在事件循环中的执行过程

要理解promise在事件循环中的流程,我们需要先理解一下消息队列和事件循环、宏任务和微任务等概念:

消息队列和事件循环(event loop)

首先我们知道js是单线程执行的,那么js在单线程中的执行场景是怎么样的?

单线程下执行任务过程

假如我们有一系列的任务需要做,比如

function task() {
	const t1 = 1 + 2;  //任务一
	const t2 = 2 + 2;  //任务二
	const t3 = 3 + 2;  //任务三
	const sum = t1 + t2 + t3;  //任务四
}
复制代码

从这些执行代码中,浏览器会把所有代码放进主线程里,等要执行时,会按照顺序一次执行任务,任务执行完就退出线程。

如果在执行任务过程中,要接受并执行新的任务,那应该怎么办呢?

事件循环和消息队列

要想在执行任务过程中,能够执行新的任务,浏览器就需要引入事件循环和消息队列,用来判断是否有新的任务要执行。具体需要引入

  1. 事件循环,需要添加for语句,判断任务是否执行完,如果还未执行,就继续执行
  2. 消息队列,主线程可以处理其他进程发过来的任务,那么就需要用消息队列存着,先进先出的

那么消息队列中的任务都是一样的优先级吗?

宏任务和微任务

消息队列里的任务有很多种类型,比如输入事件,文件读写,js定时器,promise,websock等等 如果对这些任务进行分类,可以分为宏任务和微任务。

宏任务

宏任务是浏览器在执行的,包括了

  1. 渲染事件(如解析 DOM、计算布局、绘制)
  2. 用户交互事件(如鼠标点击、滚动页面、放大缩小等)
  3. script标签中的运行代码
  4. 网络请求完成、文件读写完成事件。
  5. setTimeout定时任务

可以看出,宏任务的时间粒度比较大,执行时间不能精确控制,不满足某些实时性的需求,比如监听DOM变化的需求,为此引入了微任务。

微任务

微任务就是一个需要异步执行的函数,执行时机是在主函数执行结束后,当前宏任务结束之前。包括了

  1. promises:Promise.then、Promise.catch、Promise.finally
  2. MutationObserver
  3. queueMicrotask
  4. process.nextTick (node环境下)

promise是属于微任务的,那么promise和微任务的关联是怎么样的?

promise和微任务

为了理解promise和微任务之间的关系,我们也引入setTimeout这个宏任务来进行比较,先看以下代码

console.log('宏任务1')
setTimeout(() => {
  console.log('宏任务2')
})
Promise.resolve().then(() => {
  console.log('微任务1')
})
console.log('宏任务3')
复制代码

放在浏览器中执行,结果会是:

宏任务1
宏任务3
微任务1
宏任务2
复制代码

过程分析如下:

  1. 整个js脚本为一个宏任务来执行,先打印宏任务1和宏任务3
  2. setTimeout作为一个宏任务放入宏任务队列中
  3. promise作为一个微任务放入微任务队列中
  4. 本次js脚本宏任务执行结束之前,检查微任务,发现有一个微任务,执行,打印微任务1
  5. 进入下一个宏任务,发现setTimeout,执行,打印宏任务2

可以看出,宏任务和微任务的执行时机是不一样的,promise是作为微任务的角色在事件循环机制中执行的。

五、手写promise

Promise是V8提供的,内部的方法我们无法看得到,为了能更加清晰的理解promise原理,我们来手写一下promise,首先看一下promise实例

promise实例


function timeout() {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'done');
  });
}

timeout().then(function(value) {
	console.log(value)
}, function(error) {
	console.log(error)
})

timeout().then(function(value) {
	console.log(value)
	return timeout()
}).then(function(value) {
	console.log(value)
	// 返回字符串,而不是promise
	return 'success'
}).then(function(value) {
	console.log(value)
	// 使用resolve静态方法
	return Promise.resolve('resolve')
}).then(function(value) {
	console.log(value)
}).catch(function(err) {
	console.log(err)
})

复制代码

我们分析一下代码,会发现:

  1. Promise是一个类,需要传入一个exec执行函数,这个执行函数会马上执行
  2. Promise有三个状态
    • pendding 等待
    • fullfilled 完成
    • rejected 失败
  3. 状态不可以撤回,只能从Pendding到Fullfilled,或者从Pendding到Rejected,状态一旦更改就不可以修改
  4. Promise可以执行多次then方法,会保存对应的回调函数等待合适时机调用
  5. Promise的then方法可以实现链式调用
  6. Promise有try-catch处理,如果代码报错则状态变为Rejected

promise实现代码

1. 创建class并传入exec函数,函数马上执行

class MyPromise {
	constructor(exec) {
		exec()
	}
}
复制代码

2. 传入resolve和reject参数作为回调函数

class MyPromise {
	constructor(exec) {
		exec(this.resolve, this.reject)
	}
	resolve() {	
	}
	reject() {
	}
}
复制代码

3. 初始化Promise状态,resolve和reject函数添加状态修改逻辑

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		exec(this.resolve, this.reject)
	}
	resolve() {
		this.state = 'fullfilled'
	}
	reject() {
		this.state = 'rejected'
	}
}
复制代码

4. Promise状态只能从pendding到fullfilled或rejected

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		exec(this.resolve, this.reject)
	}
	resolve() {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
		}
	}
	reject() {
		if(this.state === 'pendding') {
			this.state = 'rejected'
		}
	}
}
复制代码

5. 保存异步返回的回调值

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		exec(this.resolve, this.reject)
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
		}
	}
}
复制代码

6. 添加then方法

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		exec(this.resolve, this.reject)
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
		}
	}
	then(onResolve, onReject) {
		if(this.state === 'fullfilled') {
			onResolve(this.value)
		}
		if(this.state === 'rejected') {
			onReject(this.value)
		}
	}
}
复制代码

7. 支持多个then方法,保存回调方法等待状态变更时调用

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		exec(this.resolve, this.reject)
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while(this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while(this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		if(this.state === 'fullfilled') {
			onResolve(this.value)
		}
		if(this.state === 'rejected') {
			onReject(this.value)
		}
		if(this.state === 'pendding') {
			this.resolveCallback.push(onResolve)
			this.rejectedCallback.push(onReject)
		}
	}
}
复制代码

8. 支持then链式调用(重点)

如果要实现链式调用,那么then方法要返回一个promise对象。但是上一个then方法中可能返回promise对象,也可能返回其他类型,那么我们需要判断类型,如果非promise,则封装成promise对象

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		exec(this.resolve, this.reject)
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while(this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while(this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		return new MyPromise((resolve, reject) => {
			if(this.state === 'fullfilled') {
				const x = onResolve(this.value)
				
				if(x instanceof MyPromise) {
					// 如果是promise对象,则调用then方法
					// x.then(value => resolve(value), err => reject(err))
					// 可简写为
					x.then(resolve, reject)
				}else {
					resolve(x)
				}
			}
			if(this.state === 'rejected') {
				onReject(this.value)
			}
			if(this.state === 'pendding') {
				this.resolveCallback.push(onResolve)
				this.rejectedCallback.push(onReject)
			}
		})
	}
}
复制代码

9. 继续处理rejected和pendding状态下的链式调用

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		exec(this.resolve, this.reject)
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while(this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while(this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		return new MyPromise((resolve, reject) => {
			if(this.state === 'fullfilled') {
				const x = onResolve(this.value)
				resolvePromise(x, resolve, reject)
			}
			if(this.state === 'rejected') {
				const x = onReject(this.value)
				resolvePromise(x, resolve, reject)
			}
			if(this.state === 'pendding') {
				this.resolveCallback.push((value) => {
					const x = onResolve(value)
					resolvePromise(x, resolve, reject)
				})
				this.rejectedCallback.push((value) => {
					const x = onReject(this.value)
					resolvePromise(x, resolve, reject)
				})
			}
		})
	}
}

// 把判断promise对象的方法封装出来
function resolvePromise(x, resolve, reject) {
	if(x instanceof MyPromise) {
		// 如果是promise对象,则调用then方法
		// x.then(value => resolve(value), err => reject(err))
		// 可简写为
		x.then(resolve, reject)
	}else {
		resolve(x)
	}
}
复制代码

10. 添加try-catch和优化then参数为可传参数

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		try {
			exec(this.resolve, this.reject)
		}catch(err) {
			this.reject(err)
		}
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while(this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while(this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		onResolve = typeof onResolve === 'function' ? onResolve : value => value
		onReject = typeof onReject === 'function' ? onReject : err => {throw err}

		return new MyPromise((resolve, reject) => {
			if(this.state === 'fullfilled') {
				try {
					const x = onResolve(this.value)
					resolvePromise(x, resolve, reject)
				}catch(err) {
					reject(err)
				}
			}
			if(this.state === 'rejected') {
				try {
					const x = onReject(this.value)
					resolvePromise(x, resolve, reject)
				}catch(err) {
					reject(err)
				}
			}
			if(this.state === 'pendding') {
				this.resolveCallback.push((value) => {
					try {
						const x = onResolve(value)
						resolvePromise(x, resolve, reject)
					}catch(err) {
						reject(err)
					}
				})
				this.rejectedCallback.push((value) => {
					try {
						const x = onReject(this.value)
						resolvePromise(x, resolve, reject)
					}catch(err) {
						reject(err)
					}
				})
			}
		})
	}
}

// 把判断promise对象的方法封装出来
function resolvePromise(x, resolve, reject) {
	if(x instanceof MyPromise) {
		// 如果是promise对象,则调用then方法
		// x.then(value => resolve(value), err => reject(err))
		// 可简写为
		x.then(resolve, reject)
	}else {
		resolve(x)
	}
}
复制代码

11. 支持 Promise.resolve 还有 Promise.reject 的用法

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		try {
			exec(this.resolve, this.reject)
		}catch(err) {
			this.reject(err)
		}
	}
	resolve(value) {
		if(this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while(this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject(value) {
		if(this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while(this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		onResolve = typeof onResolve === 'function' ? onResolve : value => value
		onReject = typeof onReject === 'function' ? onReject : err => {throw err}

		return new MyPromise((resolve, reject) => {
			if(this.state === 'fullfilled') {
				try {
					const x = onResolve(this.value)
					resolvePromise(x, resolve, reject)
				}catch(err) {
					reject(err)
				}
			}
			if(this.state === 'rejected') {
				try {
					const x = onReject(this.value)
					resolvePromise(x, resolve, reject)
				}catch(err) {
					reject(err)
				}
			}
			if(this.state === 'pendding') {
				this.resolveCallback.push((value) => {
					try {
						const x = onResolve(value)
						resolvePromise(x, resolve, reject)
					}catch(err) {
						reject(err)
					}
				})
				this.rejectedCallback.push((value) => {
					try {
						const x = onReject(this.value)
						resolvePromise(x, resolve, reject)
					}catch(err) {
						reject(err)
					}
				})
			}
		})
	}
	
	// resolve 静态方法
	static resolve (value) {
		// 如果传入 MyPromise 就直接返回
		if (value instanceof MyPromise) {
			return value
		}

		return new MyPromise(resolve =>  {
			resolve(value)
		})
	}

	// reject 静态方法
	static reject (err) {
		return new MyPromise((resolve, reject) => {
			reject(err)
		});
	}
}

// 把判断promise对象的方法封装出来
function resolvePromise(x, resolve, reject) {
	if(x instanceof MyPromise) {
		// 如果是promise对象,则调用then方法
		// x.then(value => resolve(value), err => reject(err))
		// 可简写为
		x.then(resolve, reject)
	}else {
		resolve(x)
	}
}
复制代码

完成手写promise后,我们怎么判断写的是否符合规范呢?

验证promise代码

1. 全局安装promises-aplus-tests

npm install promises-aplus-tests -g
复制代码

参考promises-aplus-tests

2. 加入deferred

MyPromise.deferred = function () {
  var result = {}
  result.promise = new MyPromise(function (resolve, reject) {
    result.resolve = resolve
    result.reject = reject
  })

  return result
}
module.exports = MyPromise;
复制代码

3. 启动命令看测试结果

发现有很多报错的,我们来逐个解决:

问题1:2.2.1和2.2.2不通过

2.2.1&&2.1.2.png

从规范来看,是说没有处理then方法的可选参数,可是我明明有处理了,很奇怪,我们看看这个npm包的处理逻辑

2.2.1判断代码.png

222.png

问题出在adapter.rejected方法的定义上,debug后,需要把MyPromise的resolve和reject方法改为箭头函数才能解决,否则会读不到this.state

2.2.1-fix.png

问题2:2.2.2 在promise完成之前不能调用它

21.png 从规范来看,需要在promise完成之前才能使用,这时,我们就可以用微任务来解决这个问题

22.png

问题3:2.3.* 都还没处理

31.png

从截图看,promise和x如果是相同的对象,会出问题,还有一些其他的要求,是我们的resolvePromise写的不够完善,优化下代码

// 封装一下函数
function resolvePromise(promise, x, resolve, reject) {
	// 如果相等了,说明返回自己,会引起循环调用问题
	if (promise === x) {
		return reject(new TypeError('The promise and the return value are the same'))
	}

	if (typeof x === 'object' || typeof x === 'function') {
		// x 为 null 直接返回
		if (x === null) {
			return resolve(x)
		}

		let then
		try {
			// 把 x.then 赋值给 then 
			then = x.then
		} catch (error) {
			// 如果出错就拒绝 promise
			return reject(error)
		}

		// 如果 then 是函数
		if (typeof then === 'function') {
			let called = false
			try {
				then.call(
					x, // this 指向 x
					// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
					y => {
						// 如果 resolvePromise 和 rejectPromise 均被调用,
						// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
						// 实现这条需要前面加一个变量 called
						if (called) return
						called = true
						resolvePromise(promise, y, resolve, reject)
					},
					// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
					r => {
						if (called) return
						called = true
						reject(r)
					})
			} catch (error) {
				// 如果调用 then 方法抛出了异常 error:
				// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
				if (called) return

				// 否则以 error 为据因拒绝 promise
				reject(error)
			}
		} else {
			// 如果 then 不是函数,以 x 为参数执行 promise
			resolve(x)
		}
	} else {
		// 如果 x 不为对象或者函数,以 x 为参数执行 promise
		resolve(x)
	}
}
复制代码

4. 再次测试

4.png

完美解决,附上完整代码如下

class MyPromise {
	constructor(exec) {
		this.state = 'pendding'
		this.value = null
		this.resolveCallback = []
		this.rejectedCallback = []
		try {
			exec(this.resolve, this.reject)
		} catch (err) {
			this.reject(err)
		}
	}
	resolve = (value) => {
		if (this.state === 'pendding') {
			this.state = 'fullfilled'
			this.value = value
			while (this.resolveCallback.length) {
				this.resolveCallback.shift()(this.value)
			}
		}
	}
	reject = (value) => {
		if (this.state === 'pendding') {
			this.state = 'rejected'
			this.value = value
			while (this.rejectedCallback.length) {
				this.rejectedCallback.shift()(this.value)
			}
		}
	}
	then(onResolve, onReject) {
		onResolve = typeof onResolve === 'function' ? onResolve : value => value
		onReject = typeof onReject === 'function' ? onReject : err => { throw err }

		const p2 = new MyPromise((resolve, reject) => {
			if (this.state === 'fullfilled') {
				queueMicrotask(() => {
					try {
						const x = onResolve(this.value)
						resolvePromise(p2, x, resolve, reject)
					} catch (err) {
						reject(err)
					}
				})
			}
			if (this.state === 'rejected') {
				queueMicrotask(() => {
					try {
						const x = onReject(this.value)
						resolvePromise(p2, x, resolve, reject)
					} catch (err) {
						reject(err)
					}
				})
			}
			if (this.state === 'pendding') {
				this.resolveCallback.push((value) => {
					queueMicrotask(() => {
						try {
							const x = onResolve(value)
							resolvePromise(p2, x, resolve, reject)
						} catch (err) {
							reject(err)
						}
					})
				})
				this.rejectedCallback.push((value) => {
					queueMicrotask(() => {
						try {
							const x = onReject(this.value)
							resolvePromise(p2, x, resolve, reject)
						} catch (err) {
							reject(err)
						}
					})
				})
			}
		})

		return p2
	}

	// resolve 静态方法
	static resolve(value) {
		// 如果传入 MyPromise 就直接返回
		if (value instanceof MyPromise) {
			return value
		}

		return new MyPromise(resolve => {
			resolve(value)
		})
	}

	// reject 静态方法
	static reject(err) {
		return new MyPromise((resolve, reject) => {
			reject(err)
		})
	}
}

// 封装一下函数
function resolvePromise(promise, x, resolve, reject) {
	// 如果相等了,说明返回自己,会引起循环调用问题
	if (promise === x) {
		return reject(new TypeError('The promise and the return value are the same'))
	}

	if (typeof x === 'object' || typeof x === 'function') {
		// x 为 null 直接返回
		if (x === null) {
			return resolve(x)
		}

		let then
		try {
			// 把 x.then 赋值给 then 
			then = x.then
		} catch (error) {
			// 如果出错就拒绝 promise
			return reject(error)
		}

		// 如果 then 是函数
		if (typeof then === 'function') {
			let called = false
			try {
				then.call(
					x, // this 指向 x
					// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
					y => {
						// 如果 resolvePromise 和 rejectPromise 均被调用,
						// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
						// 实现这条需要前面加一个变量 called
						if (called) return
						called = true
						resolvePromise(promise, y, resolve, reject)
					},
					// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
					r => {
						if (called) return
						called = true
						reject(r)
					})
			} catch (error) {
				// 如果调用 then 方法抛出了异常 error:
				// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
				if (called) return

				// 否则以 error 为据因拒绝 promise
				reject(error)
			}
		} else {
			// 如果 then 不是函数,以 x 为参数执行 promise
			resolve(x)
		}
	} else {
		// 如果 x 不为对象或者函数,以 x 为参数执行 promise
		resolve(x)
	}
}


MyPromise.deferred = function () {
	var result = {}
	result.promise = new MyPromise(function (resolve, reject) {
		result.resolve = resolve
		result.reject = reject
	})

	return result
}

module.exports = MyPromise
复制代码

六、问题回复

  1. Promise是一种异步代码编写规范
  2. 为了解决异步代码引起的回调地狱问题
  3. 通过回调函数、事件监听等异步编程方案来写代码
  4. 可参考文章中的相关例子
  5. 可参考文章中的事件循环和微任务部分
  6. 因为浏览器和node宿主环境的事件循环有差异
  7. 可参考文章中手写Promise代码部分
  8. async/await只是语法糖,本质是通过promise来实现
分类:
前端
收藏成功!
已添加到「」, 点击更改