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的第二个参数本来就是用来处理上一层状态为失败的
