浅析Promise

浅析Promise

谈到JS的异步操作,往往第一时间会想到Promise。 但是Promise是否等于异步操作呢? 答案是不。

jacascript里的异步操作是指:js引擎线程在执行到该操作时不会立即返回结果(区别于同步操作),而是将其交由其他浏览器线程进行处理,js引擎线程本身继续往下操作。 待其他现场处理完毕将回调函数放进消息队列后再由js引擎线程进行处理。

所以我们可以得出异步操作的核心特征:

  • 非阻塞性,异步操作不会阻塞后续代码的执行。
  • 回调函数,当一个异步操作完成后,他的回调函数会被调用。

我们在工作学习中常用到的promise不能和异步操作画等号,它实则是ES6新增的让我们更优雅简单地书写异步操作的一种方式。

Promise的三种状态

  • pending:初始状态,待定结果
  • resolve:操作成功
  • rejected:操作失败

状态变更方法

Promise为我们提供了两个方法用于改变Promise实例的运行状态。分别是操作成功resolve(), 操作失败reject()

resolve()

resolve()被用来敲定一个promise的成功状态。

如果入参本身就是一个Promise或其他非Promise类型,那么会作为一个Promise被返回;

当入参是一个 thenable 对象,resolve() 将调用其 then() 方法及其两个回调函数;并根据thenable的then()里最先敲定的状态返回一个promise。

实例:

javascript 复制代码
// 传入非promise
const p1 = Promise.resolve(111);
// 传入promise
const p2 = Promise.resolve(new Promise((resolve, reject) => 
	resolve(123)
));
// thenable
const p3 = Promise.resolve({
  then(onFulfill, onReject) {
    onFulfill("已兑现!");
  },
})
// thenable
const p4 = Promise.resolve({
  then(onFulfill, onReject) {
    throw new TypeError("已失败")
    onFulfill("已兑现!");
  },
})

p1.then(val => 
   console.log(val)
).catch(val => 
   console.log(val)
)
p2.then(val => 
   console.log(val)
).catch(val => 
   console.log(val)
)

p3.then(val => 
   console.log(val)
).catch(val => 
   console.log(val)
)

p4.then(val => 
   console.log(val)
).catch(val => 
   console.log(val)
)

返回值

javascript 复制代码
> 111
> 123
> "已兑现!"
> TypeError: 已失败

Promise.reject():

reject()被用来敲定一个promise的失败状态。

入参为该Promise被拒绝的原因或一个promise对象。

与resolve不同的是,如果传入的是一个promise对象,resolve会返回和入参相同的promise,而reject会返回一个新的promise。

嵌套调用

需要注意的是,如果绑定相应回调函数时 Promise 已经确定了状态(在创建时就已经执行了resolve/rejected),该回调函数将被立即调用。

javascript 复制代码
new Promise((resolveOuter) => {
  resolveOuter(
    new Promise((resolveInner) => {
      setTimeout(resolveInner => {
        console.log("inner end")}, 1000);
    }),
  );
}).then(console.log("outer end"));

返回结果

javascript 复制代码
> "outer end"
> "inner end"

通过这个返回结果可以看出就算resolveOuter里新建的Promise没有执行完,但是外部Promise状态确认后里面执行了then方法里的操作。

Promise的基本结构

javascript 复制代码
new Promise((resolve, rejected) => {

})
.then()
.catch()
.finally()

在基本结构里 (resolve, rejected) => {}) 是一个同步任务区,该区域里的代码都是同步执行的。.then() .catch()分别是成功回调和失败回调,这个区域是异步执行的。.finally()是这个promise执行完毕,无论是成功还是失败都会执行的区域,所以它是晚于.then().catch()的。

并发Promise

讲到异步执行,那我们就不得不讨论并发的情况,promise同样对并发有着很好的支持。

Promise.all() :

all()接受一个promise数组或一个字符串,返回一个promise。若有一个promise失败,则立马结束调用并返回最先失败的promise失败原因。如果所有的promise都成功了则返回一个数组,每个元素为该promise的resolve的返回值,且数组顺序与传入顺序一致。

如果传入的数组里有非promise 值,则该值被忽略直接返回,前提是all被resolve返回。

传入的promise都resolve

javascript 复制代码
const p1 = new Promise((resolve, rejected) => {
    setTimeout(resolve("111"), 1000)})

const p2 = 222
const p3 = Promise.resolve(333)

const Pall = Promise.all([p1, p2, p3]).then(values => 
	console.log(values)
)

返回值

javascript 复制代码
[111,222,333]

传入的promise有一个reject

javascript 复制代码
const p1 = new Promise((resolve, rejected) => {
    setTimeout(rejected("111失败"), 1000)
})

const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")

const Pall = Promise.all([p1, p2, p3, p4]).catch(
    val => {console.log(val)}
)

返回值

javascript 复制代码
 "111失败"

Promise.allSettled() :

allSettled()接受一个promise数组,无论传入的promise是否成功或者失败,都返回一个对象数组且每个对象都包含status:该promise的最终状态,value(resolve)/reason(reject)。

如果传入的数组里有非promise 值,则该值被认为直接resolve并返回。

实例

javascript 复制代码
const p1 = new Promise((resolve, rejected) => {
    setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")

const Pall = Promise.allSettled([p1, p2, p3, p4]).then(results => {
	for(const result of results){
      console.log(result)
    }
})

返回值

javascript 复制代码
> Object { status: "rejected", reason: "111失败" }
> Object { status: "fulfilled", value: 222 }
> Object { status: "fulfilled", value: 333 }
> Object { status: "rejected", reason: "444失败" }

Promise.any() :

any()接受一个promise数组,返回一个promise。若有一个promise成功,则立马结束调用并返回最先成功的promise返回值。如果所有的promise都失败了返回一个AggregateError报错,提示All promises were rejected。

如果传入的数组里有非promise 值,则该值被忽略并直接视为resolve。传入空数组时any()会视为直接失败。

传入的promise有resolve时

javascript 复制代码
const p1 = new Promise((resolve, rejected) => {
    setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")

const Pall = Promise.any([p1,p2, p3, p4]).then(val => {
	console.log(val)
})

返回值

javascript 复制代码
> 222

传入的promise全为reject时

javascript 复制代码
const p1 = new Promise((resolve, rejected) =>{
    setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")

const Pall = Promise.any([p1, p4]).catch(val => {
	console.log(val)
})

返回值

javascript 复制代码
> AggregateError: All promises were rejected

Promise.race():

race()接受一个promise数组作为参数,并返回一个Promise。这个返回的 promise,只会受到第一个完成的promise状态影响,当有一个promise完成时其他promise自动终止。

实例

javascript 复制代码
const p1 = new Promise((resolve, rejected) =>{
    setTimeout(() => {rejected("111失败")}, 1000)
})
const p2 = new Promise((resolve, rejected) =>{
    setTimeout(() => {resolve("222成功")}, 100)
})

const Pall = Promise.race([p1,p2]).then(
    val => {console.log(val)}
).catch(
    val => {console.log(val)}
)

返回值

javascript 复制代码
> "222成功"
相关推荐
成小白20 小时前
前端实现连词搜索下拉效果
前端·javascript
jason_yang20 小时前
vue3自定义渲染内容如何当参数传递
前端·javascript·vue.js
冲!!21 小时前
vue3存储/获取本地或会话存储,封装存储工具,结合pina使用存储
前端·javascript·vue.js
良木林1 天前
JS对象进阶
前端·javascript
超人不会飛1 天前
LLM应用专属的Vue3 Markdown组件 🚀重磅开源!
前端·javascript·vue.js
NULL Not NULL1 天前
ES6+新特性:现代JavaScript的强大功能
开发语言·前端·javascript
小高0071 天前
🚄 前端人必收:5 分钟掌握 ES2025 超实用语法
前端·javascript·面试
前端世界1 天前
前端跨域终极指南:3 种优雅解决方案 + 可运行 Demo
前端·javascript·状态模式
开发者小天1 天前
在Ant Design Vue 中使用图片预览的插件
前端·javascript·vue.js·前端框架