为什么需要promise
javascript是一门单线程语言,所以早期我们解决异步的场景时,大部分情况都是通过回调函数来进行。例如在浏览器中发送ajax请求,就是常见的一个异步场景,发送请求后一段时间服务器响应之后我们才能拿到结果,如果我们希望在异步结束之后执行某个操作,就只能通过回调函数这样的方式进行操作
var dynamicFunc = function (cb) {
setTimeout(function () {
cb()
}, 100)
}
dynamicFunc(function () {console.log(11)})
如果后续还有内容需要在异步函数结束时输出的话,就需要多个异步函数进行嵌套,非常不利于后续的维护。(回调地狱)
Promise基础
- promise会有三种状态 【进行中】【已完成】【已拒绝】,进行中状态可以更改为已完成或已拒绝,已经更高过状态后无法继续更改
- ES中Promise构造函数,需要传入一个函数,他接受两个函数参数,执行第一个参数后就会变成当前promise为已完成状态,执行第二个参数之后就会变成已拒绝状态
- 通过.then方法,即可在上一个promise达到已完成时继续执行下一个函数或promise,同时通过resolce或reject时传入的参数,即可给下一个函数或promise传入初始值
- 已拒绝的promise后续可以通过.catch方法或是.then方法的第二个参数或是try catch 进行捕获
promise规范解读
任何符合promise规范的对象或函数都可以成为promise,promise A plus规范地址:https://promisesaplus.com/。
术语
Promise: promise是一个拥有then方法的对象或函数,其行为符合本规范
具有then方法(thenable):是定义了then方法的对象或函数
值(value):指任何JavaScript的合法值
异常(exception):是适用throw 语句抛出的一个值
原因(reason):表示一个promise的欲绝原因
要求
promise的状态
一个Promise的当前状态必须为以下三种状态中的一种
- 等待态(Pending):可以变为已完成或已拒绝
- 已完成(Fulfilled):不能迁移至其他状态,必须拥有一个不可变的值
- 已拒绝(Rejected):不能迁移至其他状态,必须拥有一个不可变的原因
必须有一个then方法可以访问当前值和原因
Promise构造函数上的静态方法
- Promise.resolve
- Promise.reject
- Promise.all
- Promise.race
Promise 实现(待完善)
class Promise {
construct (handle) {
this.status = "pending"
this.value = undefined
this.fulfilledList = []
this.rejectedList = []
handle(this.triggerResolve.bind(this), this.triggerReject.bind(this))
}
triggerResolve (val) {
// 当前的promise状态已经变成了resolve 要执行后续的操作
setTimeout(() => {
if (this.status === 'pendding') {
if (val instanceof Promise) {}else {
this.status = 'fulfilled'
this.value = val
this.triggerFulfilled(val)
}
}
}, 0)
}
triggerReject () {}
triggerFulfilled () {
this.fulfilledList.forEach(item => item())
this.fulfilledList = []
}
then (onFulfilled, onRejected) {
const {value, status} = this
return new Promise((onNextFulfilled, onNextRejected) => {
function onFinalFulfilled (val) {
if (typeof val !== 'function') {
onNextFulfilled(val)
} else {
const res = onFulfilled(val)
if (res instanceof Promise) {
res.then(onNextFulfilled, onNextRejected)
} else {
onNextFulfilled(res)
}
}
}
function onFinalReject (error) {
if (typeof onRejected !== 'function') {
onNextRejected(error)
} else {
let res
try {
res = onRejected(error)
} catch(e) {
onNextRejected(e)
}
if (res instanceof Promise) {
res.then(onNextFulfilled, onNextRejected)
} else {
onNextFulfilled(res)
}
}
}
switch (status) {
case 'pendding': {
this.fulfilledList.push(onFinalFulfilled)
this.rejectedList.push(onRejected)
break
}
}
})
}
catch (onReject) {
return this.then(null, onReject)
}
static resolve (val) {
if (val instanceof Promise) {return value}
return new Promise(resolve => resolve(val))
}
static reject () {}
static all (list) {
return new Promise((resolve, reject) => {
let count = 0
const values = []
for (const [i, promiseInstance] of list.entries()) {
this.resolve(promiseInstance).then(res => {
values[i]=res
count++
if (count === list.length) {
resolve(values)
}
}, err => {
reject(err)
})
}
})
}
static race () {
// 跟all逻辑差不多
}
}