Promise使用详解

简介: JS查漏补缺系列是我在学习JS高级语法时做的笔记,通过实践费曼学习法进一步加深自己对其的理解,也希望别人能通过我的笔记能学习到相关的知识点。这一次我们来了解Promise使用详解

异步请求的处理方式

案例要求:模拟网络请求,通过请求结果来调用成功的回调函数/调用失败的回调函数

在没有使用promise之前,需要callback来调用(自己封装好并定义好名称,要使用的时候才能调用)

function requestData(url, successCallback, failureCallback) {
  // 模拟网络请求
  setTimeout(() => {
    // 拿到请求的结果
    // url传入的是aaa, 请求成功
    if (url === "aaa") {
      // 成功
      let names = ["abc", "cba", "nba"]
      successCallback(names)
    } else { // 否则请求失败
      // 失败
      let error = "请求失败, url错误"
      failureCallback(error)
    }
  }, 3000);
}

// 成功的回调函数
function successCallback(result) {
  console.log("请求成功" + result);
}

// 失败的回调函数
function failureCallback(error) {
  console.log(error);
}

requestData("aac", successCallback, failureCallback)

弊端:因为是自定义的回调函数的名称和方法,所以在开发使用的时候要查看源码知道名称和方法后才能调用函数,增加了工作量
更好的方案:统一名称 promise,并规范好所有的代码编写逻辑

Promise

Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。

简单使用:

function foo() {
// 传入的这个函数, 被称之为 executor
// > resolve: 回调函数, 在成功时, 回调resolve函数
// >reject: 回调函数, 在失败时, 回调reject函数
  return new Promise((resolve, reject) => {
    resolve("success message")
    // reject("failture message")
  })
}

const fooPromise = foo()
// 调用resolve(请求成功)会来到then方法
fooPromise.then((res) => {
  console.log(res)
}
// 调用reject(请求失败)会来到catch方法
fooPromise.catch((err) => {
  console.log(err)
})

用promise重构原来的代码去解决案例(异步请求处理):

function requestData(url,) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === "aaa") {
        // 成功
        let names = ["abc", "cba", "nba"]
        resolve(names)
      } else { 
        // 失败
        let errMessage = "请求失败, url错误"
        reject(errMessage)
      }
    }, 3000);
  })
}

// main.js
const promise = requestData("aaa")
promise.then((res) => {
  console.log("请求成功:", res)
})
promise.catch((err) => {
   console.log("请求失败:", err)
})

在node中then和catch分开会报错
promise中的then和catch可以合并,给then传入两个回调函数:

第一个回调函数, 会在Promise执行resolve函数时, 被回调
第二个回调函数, 会在Promise执行reject函数时, 被回调
const promise = requestData("aaa")
promise.then((res) => {
  console.log("请求成功:", res)
}, (err) => {
   console.log("请求失败:", err)
})

promise的三种状态

一个 Promise 必然处于以下几种状态之一:

  • _待定(pending)_:初始状态,既没有被兑现,也没有被拒绝。(resolve函数和reject函数都没有被调用)
  • _已兑现(fulfilled)_:意味着操作成功完成。(已调用resolve函数)
  • _已拒绝(rejected)_:意味着操作失败。(已调用reject函数)

当resolve函数已经被调用时,promise的状态就被确定了,这时再去调用reject函数是没有效果的,反之亦然。

Promise 的链式调用

连续执行两个或者多个异步操作(一个promise包含着多个promise)
在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。我们可以通过创造一个 Promise 链来实现连续执行两个或者多个异步操作的需求。

一个promise:

new Promise((resolve, reject) => {
  resolve('res message')
}).then(res => {
  console.log("res:", res)
}, err => {
  console.log("err:", err)
})

两个promise(当前promise的状态由传入promise决定):

const promise = new Promise((resolve, reject) => {
  // resolve("aaaaaa")
  reject("err message")
})

const newPromise = new Promise((resolve, reject) => {
  resolve(Promise)
}).then(res => {
  console.log("res:", res)
}, err => {
  console.log("err:", err)
})

Promise对象方法

// 可以通过下面代码查看Promise有哪些对象方法
console.log(Object.getOwnPropertyDescriptors(Promise.prototype))

Promise.prototype.then()

简单使用:

const promise = new Promise((resolve, reject) => {
  resolve()
})
promise.then(res => {
  console.log('res:',res)
})  // 当上面调用resolve时会调用下面的回调

同一个Promise可以被多次调用then方法,当我们的resolve方法被回调时, 所有的then方法传入的回调函数都会被调用

promise.then(res => {
  console.log("res1:", res)
})

promise.then(res => {
  console.log("res2:", res)
})

promise.then(res => {
  console.log("res3:", res)
})

then方法传入的 "回调函数: 可以有返回值,返回值是新的Promise

  • 如果我们返回的是一个普通值(数值/字符串/普通对象/undefined), 那么这个普通的值被作为一个的Promise的resolve
// 下面是一个链式调用
promise.then(res => {
  return "aaaaaa"  // 没有返回值默认返回undefined
}).then(res => {
  console.log("res:", res)
  return "bbbbbb"
})

上面代码中第二个then方法接收的值是第一个then方法返回的,且上面调用resolve是与第二个then方法无关的(注意:这里两个then方法所捕获的Promise不是同一个,第二个then方法捕获的是第一个then方法返回产生的一个的新Promise)

  • 如果我们返回的是一个Promise,则后一个的then方法所捕获的Promise取决于前一个返回的Promise
promise.then(res => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(111111)
    }, 3000)
  })
}).then(res => {
  console.log("res:", res)
})

Promise.prototype.catch()

通过catch方法来传入错误(拒绝)捕获的回调函数

简单使用:

const promise = new Promise((resolve, reject) => {
  reject()
})
promise.catch(err => {
  console.log('err:',err)
})

注意:catch捕获顺序

  1. 当上面调用的是resolve时:
  • 如果我们的catch方法是写在then方法之后的,当then方法返回的是一个普通值,那then方法和catch方法捕获的是同一个Promise。
  • 但如果then方法返回的是一个新的Promise且调用了reject/throw Error,则这个then方法之后的catch方法优先捕获的是新的Promise
const promise = new Promise((resolve, reject) => {
  resolve('111')
})
promise.then(res => {
  return new Promise((resolve, reject) => {
    reject("then rejected status")
  })
}).catch(err => {
  console.log("err:", err) // err: then rejected status
})
  1. 当上面调用的是reject时:
  • catch方法捕获的是与then方法同一个Promise,无论then方法返回的是什么值
const promise = new Promise((resolve, reject) => {
  reject('111')
})
promise.then(res => {
  return new Promise((resolve, reject) => {
    reject("then rejected status")
  })
}).catch(err => {
  console.log("err:", err) // err: 111
})

catch返回值:返回值也是新的Promise

  • 如果我们返回的是一个普通值(数值/字符串/普通对象/undefined), 那么这个普通的值被作为一个的Promise的resolve值(与then方法一样)
  • 如果我们希望后续继续执行catch,那么需要抛出一个异常

Catch 的后续链式操作

在回调的时候抛出错误之后想要再次进行新的操作则可以使用catch来实现
new Promise((resolve, reject) => {
    console.log('开始回调-------');
    resolve();
})
.then(() => {
    throw new Error('error message');

    console.log('aaa');
})
.catch(() => {
    console.log('bbb');
})
.then(() => {
    console.log('ccc');
});

在还没有开始执行之前,VSCode就已经检测出第一个then里面抛出错误之后的代码不会执行:
image.png
执行输出:
image.png
总结:当出现失败的情况时,使用catch()中断(在catch回调和抛出错误的then回调之间的then回调也是不会执行的,catch回调之后的then回调可以执行)

Promise.prototype.finally()

finally() 方法返回一个 Promise。在 promise 结束时, 无论结果是 fulfilled 或者是 rejected, 会执行指定的回调函数。
这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。这避免了同样的语句需要在 then()catch() 中各写一次的情况
const promise = new Promise((resolve, reject) => {
  // resolve("resolve message")
  reject("reject message")
})

promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
}).finally(() => {
  console.log("finally code execute")
})

Promise类方法

直接通过类名调用的方法

Promise.resolve

将普通对象转成Promise对象并调用resolve
  1. 传入普通的值
const promise = Promise.resolve({ name: "why" })
// 相当于
const promise2 = new Promise((resolve, reject) => {
  resolve({ name: "why" })
})
  1. 传入Promise
const promise = Promise.resolve(new Promise((resolve, reject) => {
  resolve("11111")
}))

Promise.reject

将普通对象转成Promise对象并调用reject
const promise = Promise.reject("rejected message")
// 相当于
const promise2 = new Promsie((resolve, reject) => {
  reject("rejected message")
})

Promise.all

所有的Promise都变成fulfilled状态时(所有Promise都调用resolve之后), 再拿到结果
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})

Promise.all([p2, p1, p3, "aaaa"]).then(res => {
  console.log(res) // [22222,11111,33333,'aaaa']
})

但是在拿到所有结果之前, 有一个promise变成了rejected状态, 那么整个promise是rejected状态(Promise.all方法会被中断)

Promise.allSettled

所有的Promise都有结果(无论是fulfilled状态还是rejected状态)之后, 再拿到结果
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})

// allSettled
Promise.allSettled([p1, p2, p3]).then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})

image.png

Promise.race

只要有一个Promise变成fulfilled状态, 那么就结束,但有一个Promise状态先变为rejected,则结束

Promise.any

等到至少有一个Promise变成fulfilled状态, 才就结束,不管有没有Promise状态先变为rejected。如果全为rejected状态则等到全部执行完才结束并执行catch方法(全部rejected状态的错误信息)
目录
相关文章
|
Kubernetes 容器 Perl
kubeadm初始化k8s集群延长证书过期时间
kubeadm初始化k8s集群延长证书过期时间
uni-app实现swiper滑动放大缩小、实现scroll-view与swiper双向联动
uni-app实现swiper滑动放大缩小、实现scroll-view与swiper双向联动
1953 0
|
JSON 安全 fastjson
BurpSuite插件 -- FastjsonScan(反序列化检测)
BurpSuite插件 -- FastjsonScan(反序列化检测)
485 0
|
小程序
uni-app:网络状态监测之onNetworkStatusChange与getNetworkType的区别与应用
1、在实际项目开发中,难免涉及到监测网络,下面来具体了解下小程序两种监测网络的方法。 2、这里配置的是 uniapp,微信小程序把 uni. 换成 wx. 即可。
2274 0
uni-app:网络状态监测之onNetworkStatusChange与getNetworkType的区别与应用
|
2月前
|
机器学习/深度学习 存储 缓存
129_量化技术:INT8与动态量化 - 推导压缩的精度损失公式
在2025年的大语言模型(LLM)时代,随着模型规模的指数级增长,部署这些庞然大物变得越来越具有挑战性。GPT-5和Claude 3等最新模型的参数量已经达到数千亿甚至上万亿,这给计算资源和内存带来了巨大压力。模型量化作为一种有效的压缩技术,正在成为解决这一挑战的关键方案。本文将深入探讨LLM量化技术,特别是INT8和动态量化方法,推导其精度损失公式,并提供2025年最新的优化策略和实现代码。
|
2月前
|
JavaScript 前端开发 安全
Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
每日激励:“如果没有天赋,那就一直重复”。我是蒋星熠Jaxonic,一名执着于代码宇宙的星际旅人。用Vue 3与TypeScript构建高效、可维护的前端系统,分享Composition API、状态管理、性能优化等实战经验,助力技术进阶。
Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
|
10月前
|
JSON 监控 API
虾皮(shopee)商品列表接口(虾皮API 系列)
虾皮(Shopee)是东南亚及台湾地区的知名电商平台,提供丰富的商品数据。通过其API接口,开发者可合法获取商品列表信息,包括商品ID、名称、价格等,支持按分类、关键词、价格范围等条件筛选。Python示例代码展示了如何使用API进行请求,并解析返回的JSON数据。应用场景涵盖市场调研、竞品分析、选品决策、价格监控及数据可视化,帮助电商从业者和分析师更好地理解市场动态,优化运营策略。
|
2月前
|
前端开发 JavaScript API
js实现promise常用场景使用示例
本文介绍JavaScript中Promise的6种常用场景:异步请求、定时器封装、并行执行、竞速操作、任务队列及与async/await结合使用,通过实用示例展示如何优雅处理异步逻辑,避免回调地狱,提升代码可读性与维护性。
251 10
|
3月前
|
存储 前端开发 安全
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
219 5
|
11月前
|
人工智能 算法 API
构建基于 Elasticsearch 的企业级 AI 搜索应用
本文介绍了基于Elasticsearch构建企业级AI搜索应用的方案,重点讲解了RAG(检索增强生成)架构的实现。通过阿里云上的Elasticsearch AI搜索平台,简化了知识库文档抽取、文本切片等复杂流程,并结合稠密和稀疏向量的混合搜索技术,提升了召回和排序的准确性。此外,还探讨了Elastic的向量数据库优化措施及推理API的应用,展示了如何在云端高效实现精准的搜索与推理服务。未来将拓展至多模态数据和知识图谱,进一步提升RAG效果。
429 1