在了解这个之前我们先了解什么是协程, 协程是比线程更轻量级的存在, 他不由 cpu 直接调度,而是可以通过用户来手动操作(通过程序), 在可以挂起,和开始, 可以理解成协程跑在线程上, 一个线程可以有很多个协程, 但是一个线程只能同时执行一个协程, A 协程可以开启 B 协程, 但是 A 协程必须让出控制权, 当 B 协程完成后,必须让出控制权, A 协程掌握控制权, 这样就可以只有一个协程在执行, 生成器函数的 yield 让函数暂停执行,并执行外面的函数, 通过 next 函数让函数重新执行, 协程带来的好处可以提升性能, 协程的切换并不像线程那样过多的消耗资源, 了解了协程, 就知道为什么要生成器函数了。
- async
- 关键字, 标识这个函数为异步, 返回一个函数返回的值是 Promise 类型数据
- await
- 关键字, 等待一个 Promise 的兑换以及值, 后面跟的是一个表达式
async / await 实现原理
是 generator 和 Promise 的语法糖, 书写异步代码如同同步代码一样, async 可以理解为, 将 generator 和 自执行器的封装, await 可以理解为 yield
// 返回一个 Promise 值
function test(num) {
return Promise.resolve(num * 3)
}
// 生成器函数有个特点, next 传入的值等于上一 yield 的返回值
function * generator() {
const value1 = yield test(2)
const value2 = yield test(vlaue1)
}
function generatorFunc(generators) {
return () => {
return new Promise((resolve, reject) => {
const gen = generators()
const doYield = (val) => {
let res
try {
res = gen.next() // 满足迭代器协议, 返回 {value: ..., done: ..}
} catch (e) {
reject(e)
}
if (res.done) { // 迭代完成
return resolve(res.value) // 返回这个最终值
} else {
// 没有迭代完成, 继续迭代
res.value.then(result => doYield(result))
}
}
doYield() // 执行这个函数
})
}
}
// 外部调用
generatorFunc(generator)()
Promise
Promise 的作用是什么?
- 解决回调地狱问题, 采用 then 的方法处理异步回调
- 统一的错误处理机制, catch 方法可以捕捉到错误的发生
- 支持链式调用,使代码简洁
- 统一的 API, 各种异步操作, 都使用同样的方法处理
thenable 对象是什么?
拥有 then 方法的函数或对象,为了兼容以前社区中实现的 then, 在 Promise 被发布前社区就存在一些实现, 需要注意一点, Promise 对象本身就是一个 thenable 对象
var o = { then: function() {} }; // o是thenable对象
var f = function() {};
f.then = function() {}; // f是thenable函数
使用 ES6 的方式实现
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
// 工具函数, 处理 then 方法
const util = (execFun, value, resolve, reject) => {
try {
const val = execFun(value)
resovel(val)
} catch (err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
// promise 的状态
this.status = PROMISE_STATUS_PENDING
// 成功的结果
this.value = undefined
// 失败的原因
this.reason = undefined
// 存放成功的回调
this.onFulFills = []
// 存放失败的回调
this.onRejecteds = []
// 成功的执行函数
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 考虑传入的值就是一个 Promise 对象, 直接将他的兑换值返回
if (value instanceof MyPromise) {
value.then(resolve, reject)
return
}
// 如果传入的值是一个 thenable
if (value !== null && (typeof value === 'function' || typeof vlaue === 'object')) {
let then
try {
then = value.then
} catch (err) {
reject(err)
}
// 如果 then 是一个函数, 可以认为他符合条件
if (typeof then === 'function') {
let called = false // 避免多次调用, 避免 resolve 的时候又传入 Promsie 对象,因为 Promsie 本身就是一个 thenable 对象
try {
then.call(value, (res) => {
if (called) return
called = true
resovle(res)
}, (rej) => {
if (called) return
called = true
reject(rej)
})
} catch (err) {
reject(err)
}
}
}
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulFills.forEach(fn => {
fn(this.value)
})
})
}
}
// 失败的执行函数
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 考虑传入的值就是一个 Promise 对象, 直接将他的兑换值返回
if (value instanceof MyPromise) {
value.then(resolve, reject)
return
}
// 如果传入的值是一个 thenable
if (value !== null && (typeof value === 'function' || typeof vlaue === 'object')) {
let then
try {
then = value.then
} catch (err) {
reject(err)
}
// 如果 then 是一个函数, 可以认为他符合条件
if (typeof then === 'function') {
let called = false // 避免多次调用
try {
then.call(value, (res) => {
if (called) return
called = true
resovle(res)
}, (rej) => {
if (called) return
called = true
reject(rej)
})
} catch (err) {
reject(err)
}
return
}
}
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING ) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejecteds.forEach(fn => {
fn(this.reason)
})
})
}
}
// 执行函数
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
// ==== 原型身上的方法 ====
// 实现 then 方法
then (onFulfilled, onRejected) {
// 当不传 onRejected 回调函数, 也能将状态传递下去
const defaultOnRejected = (err) => {
throw err
}
onRejected = onRejected || defaultOnRejected
// 当不传 onFulfilled 回调函数, 也能将状态传递下去
const defaultOnRejected = (value) => value
onFulfilled = onFulfilled || defalultOnRejected
// 上面的 default 作用是, 即使不传对应回调函数, 也会默认将状态传递下去, 解决链式掉调用时出现的问题
return new MyPromise ((resolve, reject) => {
// 状态已经锁定, 再调用 then 方法, 判断状态, 并且要传入对应回调函数后再执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
util(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
util(onRejected, this.reason, resolve, reject)
}
// 状态还没有被锁定
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulFills.push((value) => {
util(onFulfilled, value, resolve, reject)
})
this.onRejecteds.push(reason => {
util(onRejected, reason, resolve, reject)
})
}
})
}
// 当出现错误时可以捕获错误结果, MDN 上对他的描述是 Promise.prototype.then(undefined, onRejected) 的简写
catch (onRejected) {
return this.then(undefined, onRejected)
}
// Promise.prototype.then(onFinally, onFinally) 的简写, 不接收任何值, 与上一个 Promise 保持等效的状态
/**
等效Promise指的是两个Promise对象在行为上是相同的,
即它们的状态(fulfilled、rejected)和值(或错误)是相同的。
这意味着如果你有一个Promise P,另一个Promise Q是等效于P的,那么无论P是成功还是失败,Q都会以相同的方式成功或失败。
then方法返回的新Promise是指
当你调用一个Promise的.then()方法时,这个方法会返回一个新的Promise对象。
这个新的Promise对象会根据原Promise对象的状态和.then()方法中提供的处理函数来决定自己的状态和值。
如果原Promise成功,.then()方法中的成功处理函数会被调用,其返回值(或抛出的错误)将决定新Promise的状态和值;
如果原Promise失败,.then()方法中的失败处理函数会被调用,其返回值(或抛出的错误)将决定新Promise的状态和值。
*/
finally (onFinally, onFinally) {
return this.then( () => onFinally(), () => onFinally())
}
}
// ===== 静态方法 =====
static resolve (value) {
return new MyPromise((resolve, reject) => resolve(value))
}
static reject (reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
// 接收一个 Promise 可迭代数组,当出现错误时会返回带错误的 Promise 结果值, 如果都成功被兑现会返回一个带成功值的 Promise 数组对象
static all (promises) {
return new MyPromise((resolve, reject) => {
// 用于存储成功的值
const values = []
promises.forEach(item => {
try {
item.then(res => {
values.push(res)
if (values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
} catch (err) {
reject(err)
}
})
})
}
// 和 all 方法类似, 但是返回的值结构有所不同, 并且他会记录所有的结果
static allSettled (promises) {
return new Promise((resolve, reject) => {
const values = []
promises.forEach(item => {
try {
item.then(res => {
values.push({
status: PROMISE_STATUS_FULFILLED
value: res
})
if (values.length === promises.length) {
resolve(values)
}
}, err => {
values.push({
status: PROMISE_STATUS_REJECTED
reason: err
})
if(vlaues.length === promises.length) {
resovle(values)
}
})
} catch (err) {
reject(err)
}
})
})
}
// 返回最快被兑现的值, 无论是失败还是成功的结果
static race (promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve, reject)
})
})
}
// 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。
// 当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝, 这句话表明我们需要记录所有的拒绝原因, 当他全部失败时会返回出去
static any (promises) {
return new MyPromise((resovel, reject) => {
const reasons = []
promises.forEach(promise => {
promise.then(resovle, err => {
reasons.push(err)
if (reasons.length === promise.length) {
reject(new AggregateError(reaons, 'All promise were rejected'))
}
})
})
})
}
}
ES5 实现
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function MyPromise (executor) {
const _this = this
this.status = PROMISE_STATUS_PENDING
this.value = undefinde
this.reason = undefinde
this.onFulfills = []
this.onRejected = []
function resovle (value) {
if (_this.status === PROMISE_STATUS_PENDING) {
_this.value = vlaue
_this.status = PROMISE_STATUS_FULFILLED
// 执行成功的函数
_this.onFulfills.forEach(fn => {
fn(_this.value)
})
}
}
function reject (reason) {
if (_this.status === PROMISE_STATUS_PENDING){
_this.reason = reason
_this.status = PROMISE_STATUS_REJECTED
_this.onRejecteds.forEach(fn => {
fn(_this.reason)
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// then 方法
MyPromise.prototype.then = (onFulfill, onReject) => {
// 什么也不传, 也要将状态传递下去, 满足 then 值传递特性
onFulfill = onFulfill ? onFulfill : (value) => value
onReject = onReject ? onReject : (err) => throw err
const promise = new Promise((resolve, reject) => {
// 处理状态已经敲定后再调用 then 方法的情况
if (this.staus === PROMISE_STATUS_FULFILLED){
util(onFulfill, this.value, resovle, reject)
}
if (this.status === PROMISE_STATUS_REJECTED) {
util(onReject, this.reason, resovle, reject)
}
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfills.push(() => {
queueMicrotask(() => {
try {
const val = onFulfill(this.value)
util(promise, val, resolve, reject)
} catch (err) => {
reject(err)
}
})
})
this.onRejecteds.push(() => {
queueMicrotask(() => {
try {
const reason = onReject(this.reason)
util(promise, reason, resolve, reject)
} catch (err) {
reject(err)
}
})
})
}
})
return promise
}
// 处理返回值, 与 Es6 实现的不同是, then 返回值都放在这里面处理了
function util (Promsie, value, resovle, reject) {
// 这一步是为什么?用户的返回值可能就是调用的那个 promise 对象(无法预测用户的行为)
if (Promise === value) {
reject(new Error("请避免循环引用"))
}
let called // 防止被多次调用
if (value != null && (typeof value === "function" || typeof value === "object")) {
let then
try {
then = value.then
} catch (err) {
reject(err)
}
if (typeof then === "function") {
try {
then.call(value, (y) => {
if (called) return
called = true
util(Promise, y, resovle, reject) // 直到他是一个非 thenable 的值
}, (err) => {
if (called) return
called = true
reject(err)
})
} catch (err) {
reject(err)
}
} else {
resovle(value)
}
} else {
resovle(value)
}
}
MyPromise.prototype.catch = function (onReject) {
return this.then(undefined, onReject)
}
MyPromise.prototype.finally = function (onFinally, onFinally) {
return this.then(() => onFinally(), () => onFinally())
}
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
const values = []
try {
promises.forEach(promise => {
promise.then(res => {
values.push(res)
if (values.length === promises.length) {
resovle(values)
}
}, err => {
reject(err)
})
})
} catch (err) {
reject(err)
}
})
}
MyPromise.allSettled = function (promises) {
return new MyPromise((resovle, reject) => {
const values = []
try {
promises.forEach(promise => {
promise.then(res => {
values.push({
status: PROMISE_STATUS_FULFILLED,
value: res
})
if (values.length === promises.length) {
resovle(values)
}
}, err => {
values.push({
status: PROMISE_STATUS_REJECTED
reason: err
})
if(vlaues.length === promises.length) {
resovle(values)
}
})
})
} catch (err) {
reject(err)
}
})
}
MyPromise.race = function (promises) {
return new MyPromise((resovle, reject) => {
try {
promises.forEach(promise => {
promise.then(resovle, reject)
})
} catch (err) {
reject(err)
}
})
}
MyPromise.any = function (promises) {
return new MyPromise((resovle, reject) => {
const reasons = []
try {
promsies.forEach ((promise) => {
promise.then(resolve, err => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reaons, 'All promise were rejected'))
}
})
})
} catch (err) {
reject(err)
}
})
}
免费试用
更多热门智能应用