Promise全解析
Promise全解析
面试|2023-11-20|最后更新: 2024-3-10
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里没有执行resolvereject以及throw的话,则状态也是pendingpending状态下的promise不会执行对应回调函数。
  • 每个then的参数是上一个then的return 内容
  • 错误捕获后,如果没有再throw错误,则执行后面的then。

缺点

  1. 错误必须被捕获(不捕获反应不到外面)。
  1. 需要写回调函数。
  1. 一旦新建就会立即执行,无法中途取消。
  1. 无法得知pending状态,当处于 pending 时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

API

executor

executor作为接收resolvereject的函数。 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或字符串rejectedfulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值。

完整实现

Promise的实现

  • 维护一个fullfilled的事件队列和一个rejected事件队列
  • Promise.then方法里需要判断一下当前Promise的状态以及参数类型
  • 最后需要实现两个事件队列的自执行,用来处理链式调用的情况
  • 在执行方法时使用setTimeout模拟异步任务
代码链接

一些题

并发限制

实现 Scheduler.add() 函数
答案
根据当前请求数,如果超过限制,就使用新的 promise 来进堵塞后续的请求,把 promise 的 resolve 函数传入一个数组中,然后执行完的请求结束后之前队列最前面的resolve。

重试多次

答案

支持取消的重试

实现一个轮询方法,返回一个取消方法,能够强制中断轮询
当异步方法成功时,通过回调返回结果并且结束轮询;当异步方法失败时,隔一段时间进行重试,且每次重试的时间是上一次的两倍(第一次的重试时间为 1s)。
实现
如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到:then的第二个参数本来就是用来处理上一层状态为失败的
 
 
 

参考

 
vue3 最佳实践prisma学习
Loading...