一. 概述
1. 异步模式
- 异步模式的 api 不会等待这个任务的结束才开始下一个任务
- 对于耗时操作(异步操作)开启过后就立即往后执行下一个任务
- 后续逻辑一般会通过回调函数的方式定义
2. 回调函数
- 所有异步编程方案的根基
- 由调用者定义,交给执行者执行的函数
3. Promise
-
CommonJs 社区提出了 Promise 规范
-
在 ECMA 2015 中被标准化,成为语言规范
-
Promise 实际是一个对象,用来表示一个异步任务在执行过后是成功还是失败,状态一旦确定,不会改变
-
状态
- pending 等待
- fulfilled 成功 -> onFulfilled
- rejected 失败 -> onRejected
-
基本用法
const promise = new Promise((resolve, reject) => { // resolve(100) // 成功 reject(new Error('promise rejected')) // 失败 }) promise.then(res => { console.log(res) }, err => { console.log(err) })
-
Promise 使用案例
function ajax(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open('GET', url) xhr.responseType = 'json' xhr.onload = function () { if (this.status === 200) { resolve(this.response) } else { reject(new Error(this.statusText)) } } xhr.send() }) }
-
Promise 链视调用
- Promise 对象的 then 方法会返回一个权限的 Promise 对象
- 后面的 then 方法就是在为上一个 then 方法返回的 Promise 注册回调
- 前面的 then 方法中回调函数的返回值会作为后面 then 方法回调的参数
- 如果回调返回的是 Promise,后面的 then 方法的回调会等待它的结束
const { resolve } = require("path") const promise = new Promise((resolve, reject) => { resolve(1) }) promise.then(res => { console.log(res) return new Promise(resolve => { resolve(2) }) }).then(res => { console.log(res) })
-
Promise 静态方法
- Promise.resolve() 返回一个状态为 fulfilled 的 Promise 对象
- Promise.reject() 返回一个状态为 rejected 的 Promise 对象
- Promise.all() 并行执行,等待所有任务结束才结束,需要一个数组作为参数,数组中存放通过 promise 实现的异步任务,返回一个 Promise 对象
- Promise.race() 并行执行,等待其中一个任务结束就结束,需要一个数组作为参数,数组中存放通过 promise 实现的异步任务,返回一个 Promise 对象
-
宏任务和微任务
- 宏任务:回调队列中的任务
- 微任务:宏任务执行过程中可以的一些额外需求,Promise 的回调作为微任务执行
- 常见微任务:
- Promise 回调
- MutationObserver
- process.nextTick()
- 常见微任务:
二. Promise 源码
1. 须知
- Promise 是一个类,在执行这个类的时候需要传递一个执行器,执行器会立即执行
- Promise 中有三种状态
- 成功 fulfilled
- 失败 rejected
- 等待 pending
- pending 可以转变为 fulfilled
- pending 可以转变为 rejected
- 一旦状态改变就不能更改
- resolve 和 reject 函数是用来更改状态
- resolve 是把状态变为成功
- reject 是把状态变为失败
- then 方法内部就是判断状态,如果状态为成功,调用成功回调函数,如果状态失败,调用失败回调函数,then 方法是被定义在原型对象中
- then 成功回调有一个参数,表示成功之后的值,then 失败回调有一个参数,表示失败之后的错误
- 同一个 promise 对象下面的 then 方法是可以被调用多次的
- then 方法是可以被链式调用的, 后面 then 方法的回调函数拿到值的是上一个 then 方法的回调函数的返回值
2. 模拟 Promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
status = PENDING
value = undefined
error = undefined
successCallback = []
failCallback = []
resolve = value => {
if (this.status !== PENDING) {
return
}
this.status = FULFILLED
this.value = value
while (this.successCallback.length) {
this.successCallback.shift()()
}
}
reject = error => {
if (this.status !== PENDING) {
return
}
this.status = REJECTED
this.error = error
while (this.failCallback.length) {
this.failCallback.shift()()
}
}
then(successCallback, failCallback) {
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : error => { throw error }
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
const x = failCallback(this.error)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallback.push(() => {
setTimeout(() => {
try {
const x = failCallback(this.error)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise2
}
finally(callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, error => {
return MyPromise.reject(callback()).then(undefined, () => { throw error })
})
}
catch(failCallback) {
return this.then(undefined, failCallback)
}
static all(array) {
let result = []
let index = 0
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value
index++
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
const current = array[i]
if (current instanceof MyPromise) {
current.then(value => addData(i, value), error => reject(error))
} else {
addData(i, current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(error) {
if (error instanceof MyPromise) {
return error
}
return new MyPromise(undefined, reject => reject(error))
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(X)
}
}
module.exports = MyPromise
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!