通常前端了解eventloop的时候, 最想知道代码执行的前后顺序,并不是分析EventLoop。因此这里先说总结。 为何?由于面试常考这个😂,由于分析和听懂分析都费劲。javascript
##1、总结html
ps: 对纯前端而言,掌握Promise.prototype.then、async await 和 setTimeout 的区别就能够了。另外,Promise、async await是能够转换的,可是浏览器版本问题,async await 的优先级可能高于 Promise(能够忽略这种状况)。前端
测试题目:java
const fn1 = await function () {
await fn2()
console.log(1)
}
async function fn2 () {
await console.log(2)
}
fn1()
setTimeout(function () {
console.log(3)
})
new Promise(function (resolve, reject) {
console.log(4)
resovle()
}).then(function () {
console.log(5)
}).then(function () {
console.log(6)
})
// 答案
// 2
// 4
// 1
// 5
// 6
// 3
复制代码
分析:git
代码转换分析github
function fn1 () {
new Promise(function(resolve, reject) {
console.log(2)
resolve()
}).then(function () {
console.log(1)
})
}
fn1()
setTimeout(function () {
console.log(3)
})
new Promise(function (resolve) {
console.log(4)
resolve()
}).then(function () {
console.log(5)
}).then(function () {
console.log(6)
})
复制代码
阮一峰eventloop www.ruanyifeng.com/blog/2013/1… 看内存分析的这篇 github.com/baiyuze/not…面试
了解过,能够跳过设计模式
看这篇:juejin.im/entry/59996… 以为分析有点啰嗦,没有提取关键信息promise
了解过,能够跳过浏览器
MDN文档 的 Promise 执行流程图:
了解代码第一步,必定要知道他的设计模式,可以节约至关看代码时间。Promise 代码 最主要的模式,观察者模式
封装一个简易的Promise的 resolve 和 then,便于理解 Pomise 的封装解构
class Que {
_queueLit = []
constructor (handler) {
handler.call(this, this._resolve)
}
_queue (cb) {
setTimeout(cb)
}
_resolve = () => {
const { _queueLit, _queue } = this
const resolve = function () {
let cb
while (cb = _queueLit.shift()) {
cb()
}
}
_queue(resolve)
}
then (cb) {
this._queueLit.push(cb)
return this
}
}
// test
setTimeout(() => {
console.log(4)
});
new Que(function (resolve) {
console.log(1)
resolve()
}).then(function () {
console.log(2)
}).then(function () {
console.log(3)
})
// 结果
// 1
// 4
// 2
// 3
复制代码
后记:否则发现 setTimeout 执行的 callback 为何是全局的,以及 await 为何不能在全局环境下,只能在函数内?缘由是为了加入异步队列。
上面的封装的代码,简单理解 Promise 封装的解构,如今梳理 Promise的解构,可知道 promise 的根本的两个方法: then 和 _resolve , _queues、_status。reject 、catch等都是在此基础上上进行二次封装。下列数列梳理几个点:
Promise
时的处理方式setTimeout(run)
中 ,先进先出执行异步队列_queues
是里面是多个观察者,这里根据其余人说的,要实现一个 1 对 1 的观察者模式。源码地址--> coderlt.coding.me/2016/12/04/…
uml 类图
拿到源码,将源码错误检测、不须要分析的方法统统干掉,避免混淆视听,获得以下代码:
// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
const StatusType = {
PENDING: 'PENDING',
FULFILLED: 'FULFILLED',
}
class MyPromise {
_status = StatusType.PENDING // 添加状态
_value = undefined // 添加状态
_fulfilledQueues = [] // 添加成功回调函数队列
constructor(handle) {
handle(this._resolve.bind(this))
}
_resolve(val) {
const run = () => {
if (this._status !== StatusType.PENDING) return
const runFulfilled = (value) => {
let cb
while (cb = this._fulfilledQueues.shift()) {
cb(value)
}
}
if (val instanceof MyPromise) {
const resolvePromise = val
resolvePromise.then(value => {
this._value = value
this._status = StatusType.FULFILLED
runFulfilled(value)
})
} else {
this._value = val
this._status = StatusType.FULFILLED
runFulfilled(val)
}
}
setTimeout(run)
}
then(onFulfilled) {
const {
_value,
_status
} = this
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext) => {
// 封装一个成功时执行的函数
let fulfilled = value => {
let res = onFulfilled(value)
if (res instanceof MyPromise) {
res.then(onFulfilledNext)
} else {
// 下一个 promise 的 resolve 方法的执行
onFulfilledNext(res)
}
}
switch (_status) {
case StatusType.PENDING:
/* 相当重要的代码 */
this._fulfilledQueues.push(fulfilled)
/* 相当重要的代码 end */
break
case StatusType.FULFILLED:
fulfilled(_value)
break
}
})
}
}
复制代码
怎么理解,特简单,不用想那么负责。就当 aysnc await 其实就是 promise 的语法糖。
验证:
function a () {
console.log('a')
return 'a'
}
async function b () {
const res = await a('a')
return res
}
b().then(res => {
console.log('this is', res)
})
const p = Promise.resolve(b)
console.log('b() is promise', b() instanceof Promise)
console.log('p is promise', p instanceof Promise)
// b() is promise true
// p is promise true
// this is a
复制代码
分析到这里,基本了解的 promise.then 和 resolve 的实现。reject 至关于 promise 的 resolve 的翻版,catch、all、race 就不在话下,简而言之,promise 源码最终重要的封装是 promise.then 和 resolve.