Promise全解析
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item
一句话总结Promise
用于解决异步操作结束后的方法执行问题。
原理
通过观察者模式,将要执行的函数放入一个队列里,在异步函数执行结束后执行这个队列。
Promise是JavaScript中用于处理异步操作的一种机制,它提供了一种更优雅、可靠的方式来处理异步编程。Promise的实现原理可以通过以下几个关键点来解释:
构造函数:Promise构造函数接受一个执行器函数(executor),在构造函数被调用时立即执行该函数。执行器函数接受两个参数,分别是resolve和reject,它们是两个函数,用于处理Promise的状态。
状态管理:Promise具有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。初始状态为pending,执行器函数中的resolve函数将Promise状态从pending变为fulfilled,而reject函数将Promise状态从pending变为rejected。一旦状态发生变化,就不能再次改变。
then方法:Promise实例具有一个then方法,它接受两个回调函数作为参数,分别是onFulfilled和onRejected。当Promise状态变为fulfilled时,会调用onFulfilled回调函数;当Promise状态变为rejected时,会调用onRejected回调函数。then方法返回一个新的Promise实例,使得可以进行链式调用。
链式调用:then方法返回的新Promise实例可以通过返回一个新的值或另一个Promise实例来传递结果。这种机制允许在多个异步操作之间进行串联,形成更复杂的异步流程。
错误处理:Promise提供了catch方法用于处理异常情况。catch方法是then方法的一个特殊形式,用于捕获Promise链中的任何拒绝(rejected)状态,并执行相应的错误处理逻辑。
异步执行:Promise的执行是异步的,它会将执行器函数中的代码放入任务队列中,在主线程空闲时执行。这样可以避免阻塞主线程,提高应用的响应性能。
诞生原因
最开始解决异步函数的方法是回调函数,将要执行的函数作为参数,传入异步操作中。导致会无限嵌套,也就是回掉地狱,影响代码可读性。例如
asyncfn1(asyncfn2(asyncfn3()))
。特点
- 不受外界影响,由执行函数内部决定成功和失败,且执行函数return没用,需要通过两个回调参数来决定状态。
- 一个
Promise
必然处于以下三种状态之一: - 执行态
(pending)
: 初始状态,既没有成功,也没有失败。 - 实现态
(fulfilled)
: 意味着操作成功完成。 - 拒绝态
(rejected)
: 意味着操作失败。
- 必须给
Promise
对象传入一个执行函数,否则将会报错。
- 当Promise被创建时就已经开始执行。
- Promise中有
throw
的话,就相当于执行了reject
。
- Promise只以
第一次为准
,第一次成功就永久为fulfilled
,第一次失败就永远状态为rejected
,执行了resolve
,Promise状态会变成fulfilled
,执行了reject
,Promise状态会变成rejected
。
- Promise里没有执行
resolve
、reject
以及throw
的话,则状态也是pending
,pending
状态下的promise不会执行对应回调函数。
- 每个then的参数是上一个then的return 内容
- 错误捕获后,如果没有再throw错误,则执行后面的then。
缺点
- 错误必须被捕获(不捕获反应不到外面)。
- 需要写回调函数。
- 一旦新建就会立即执行,无法中途取消。
- 无法得知
pending
状态,当处于pending
时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
API
executor
executor作为接收
resolve
和reject
的函数。
resolve
是用于处理操作成功结束的情况,会将promise
对象的状态从执行态转为成功态,并将异步操作的结果作为参数传递出去。
reject
是用于处理操作失败的情况,将promise
对象的状态从执行态转为失败态,并将错误作为参数传递出去。原型方法
Promise.prototype.then(onFulfilled,onRejected)
将成功和失败的执行函数传入promise,返回一个新的promise,将返回值做为resolve。
Promise.prototype.catch(onRejected)
只处理失败情况,相当于
Promise.prototype.then(undefined, onRejected)
Promise.prototype.finally(onFinally)
不管成功失败都会执行的函数,并且会把之前的值原封不动的传递给后面的then
方法
resolve(value)
返回一个带有成功值的promise对象,如果参数是promise,则返回参数。
reject(value)
返回一个带有拒绝值的promise对象,如果参数是promise,则返回参数。
all(iterable)
返回一个promise,执行参数迭代器中所有的promise,如果都正确,则返回一个所有promise结果的列表,如果有一个失败,则返回第一个失败结果。
race(iterable)
返回一个promise,执行参数迭代器中所有的promise,返回最先执行完成的promise结果。
any(iterable)
返回一个promise,执行参数迭代器中所有的promise。只要参数实例有一个变成
fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。allSettled(iterable)
返回一个promise,执行参数迭代器中所有的promise,只有等到所有参数实例都返回结果,才会结束。返回一个所有promise结果的列表,每个对象都有
status
属性,该属性的值只可能是字符串fulfilled
或字符串rejected
。fulfilled
时,对象有value
属性,rejected
时有reason
属性,对应两种状态的返回值。完整实现
Promise的实现
- 维护一个
fullfilled
的事件队列和一个rejected
事件队列
- 在
Promise.then
方法里需要判断一下当前Promise的状态以及参数类型
- 最后需要实现两个事件队列的自执行,用来处理链式调用的情况
- 在执行方法时使用
setTimeout
模拟异步任务
代码链接
一些题
并发限制
实现 Scheduler.add() 函数
答案
根据当前请求数,如果超过限制,就使用新的 promise 来进堵塞后续的请求,把 promise 的 resolve 函数传入一个数组中,然后执行完的请求结束后之前队列最前面的resolve。
重试多次
答案
支持取消的重试
实现一个轮询方法,返回一个取消方法,能够强制中断轮询
当异步方法成功时,通过回调返回结果并且结束轮询;当异步方法失败时,隔一段时间进行重试,且每次重试的时间是上一次的两倍(第一次的重试时间为 1s)。
实现
如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到:then的第二个参数本来就是用来处理上一层状态为失败的