详解Promise使用

news2024/11/19 13:33:28

Promise

      • 引入Promise
      • Executor
      • resolve不同值的区别
      • then方法
      • catch方法
      • finally方法
      • resolve类方法
      • reject类方法
      • all类方法
      • allSettled方法
      • race方法

引入Promise

在这里插入图片描述

我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟);

如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去;

如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息;

function requestData(url, successCallback, failtureCallback) {
    // 模拟网络请求
    setTimeout(() => {
        if (url === 'codewhy') {
            let names = ['abc', 'bcd', 'nba']
            successCallback(names)
        } else {
            let errMessage = '请求失败'
            failtureCallback(errMessage)
        }
    }, 3000)
}

requestData('codewhy',
// 成功
    (res) => {
        console.log(res)
//失败
    }, (err) => {
        console.log(err)
    })

在上面代码中,我们确实可以解决请求函数得到结果之后,获取对应的回调,但是它存在两个主要的问题:

  1. 我们需要自己来设计回调函数,回调函数的名称、回调函数的使用等等;
  2. 对于不同的人,不同的框架设计出来的方案是不同的,那么我们必须耐心去看别人的源码或者文档,以便可以理解它这个函数到底怎么用的;

PromiseAPI

Promise是一个类,可以翻译成承诺、许诺、期约;

当我们需要给予调用者一个承诺:我给你回调数据时,就可以创建一个Promise的对象

在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor

  • 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;
  • 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
  • 当我们调用reject回调函数时,会立即执行Promise对象的catch方法传入的回调函数;

Promise的代码结构:

const promise = new Promise((resolve,reject) =>{
    // pending状态:待定
    resolve("成功")
    reject("失败")
})
	// fulfilled状态: 已兑现 
promise.then(res=> {
    console.log(res)
})
	//rejected状态:已拒绝
promise.catch(err=>{
    console.log(err)
})

上面Promise使用过程,我们可以将它划分为三个阶段:

  1. 待定(pending):初始状态,既没有兑现,也没有拒绝;当执行executor中代码时,处于该状态;
  2. 已兑现(fulfilled) :意味着操作成功完成;执行了resolve时,处于该状态;
  3. 已拒绝(rejected):意味着操作失败;执行了reject时,处于该状态;

Promise重构请求

有了Promise,我们就可以将之前的代码进行重构了:

function requestData(url){
    return new Promise((resolve,reject) =>{
        setTimeout(() =>{
            if(url === "https://www.csdn.net"){
                resolve("成功")
            }else{
                reject("失败")
            }
        },1000)
    })
}

Executor

Executor是在创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数:

new Promise((resolve,reject) => {
	console.log("executor代码")
})

通常我们会在Executor中确定我们的Promise状态:

  • 通过resolve,可以兑现(fulfilled)Promise的状态,我们也可以称之为已决议(resolved);
  • 通过reject,可以拒绝(reject)Promise的状态

注意:状态一旦确定下来,那么就是不可更改的

在我们调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成兑现 (fulfilled)

在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不执行,而是无法改变Promise的状态)

resolve不同值的区别

情况一:如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数

	new Promise((resolve,reject) =>{
        resolve('normal message')
    }).then(res=>{

    },err=>{
        
    })

情况二:如果resolve中传入的是另一个Promise,那么这个新Promise会决定原Promise状态:

const newPromise = new Promise((resolve,reject) => {
    resolve("我是新的值")
})

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

情况三:如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行改then方法,并且根据then方法的结果来决定Promise的状态:

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

then方法-接受两个参数

then方法是Promise对象上的一个方法:它其实是放在Promise的原型上的Promise.prototype.then

then方法接受两个参数:

  • fulfilled的回调函数:当状态变成fulfilled时会回调的函数;
  • reject的回调函数:当状态变成reject时会回调的函数;
promise.then(res=>{
        console.log(res)
    },err =>{
        console.log(err)
    })
    // 等价于:
    promise.then(res =>{
        console.log(res)
    }).catch(err =>{
        console.log(err)
    })

then方法

then方法可以多次调用

一个Promise的then方法是可以多次调用的;

每次调用我们都可以传入对应的fulfilled回调;

当Promise的状态变成fulfilled的时候,这些回调函数都会被执行;

then(res =>{
    console.log(res)
})

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

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

then方法的返回值

then方法本身是由返回值的,它的返回值是一个Promise,所以我们可以进行链式调用:

但是then方法返回的Promise到底是一个什么样的状态呢?

Promise有三种状态:

当then方法中的回调函数本身在执行的时候,那么它处于pending状态;

当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;

  • 情况一:返回一个普通的值;
  • 情况二:返回一个Promise;
  • 情况三:返回一个thenable的值;

当then方法抛出一个异常时,那么它处于reject状态;

catch方法

catch方法的多次调用

catch方法也是Promise对象上的一个方法:它也是放在Promise的原型上的Promise.prototype.catch

一个Promise的catch方法时可以被多次调用的;

每次调用我们都可以传入对应的reject回调;

当Promise的状态变成reject的时候,这些回调函数都会被执行;

promise.catch(err=>{
    console.log(err)
})

promise.catch(err=>{
    console.log(err)
})

catch方法-返回值

事实上catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法:

const promise = new Promise((resolve,reject) =>{
    reject('rejected message')
})
promise.then(res=>{

},err=>{
    console.log(err)
    return new Promise((resolve,reject) =>{
        resolve('js人柱力')
        // reject("你好")
    })
}).then(res =>{
    console.log('res',res) // js人柱力
},err=>{
    console.log("err",err)
})

finally方法

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象变成fulfilled还是reject状态,最终都被执行的代码

finally方法是不接受参数的,因为无论前面是fulfilled状态,还是reject状态,它会执行。

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

promise.then(res =>{
    console.log("res:",res)
}).catch(err =>{
    console.log(err)
}).finally(()=>{
    console.log("我执行了") //不管是resolve 还是 reject都会执行
})

resolve类方法

前面的then、catch、finally方法都属于Promise的实例方法,都是存放在Promise的prototype上的

现在我们来学习一下Promise的类方法。

Promise.resolve的用法相当于new Promise ,并且执行resolve操作:

const promise = Promise.resolve({name:'why',age:19})
console.log(promise)
//相当于
const promise2 =new Promise((resolve,reject) =>{
    resolve({name:'why',age:19})
})
console.log(promise2)

resolve参数的形态:

  • 情况一:参数是一个普通的值或者对象
  • 情况二:参数本身是Promise
  • 情况三:参数是一个thenable

reject类方法

reject方法类似于resolve方法,只是会将Promise对象的状态设置为reject状态

Promise.reject的用法相当于new Promise ,只是会调用reject:

const promise = Promise.reject('rejected message')

// 相当于
 const promise2 = new Promise((resolve,reject) =>{
     reject("rejected message")
 })
 promise2.then(res =>{

 }).catch(err=>{
     console.log(err)
 }) 

Promise.reject传入的参数无论是什么形态,都会直接作为reject状态的参数传入到catch的

all类方法

Promise.all作用:将多个Promise包裹在一起形成一个新的Promise;

新的Promise状态由包裹的所有Promise共同决定:

当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;

当有一个Promise状态为reject时,新的Promise状态为reject,并且将第一个reject的返回值作为参数

// 创建多个Promise
const p1 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('11111')
    },1000)
})

const p2 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('222222')
    },2000)
})

const p3 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('333333')
    },5000)
})

// 所有Promise 都变成fulfilled
// all类方法也是返回的是Promise
Promise.all([p1,p2,p3,'abc']).then(res =>{
    console.log(res)
}).catch(err=>{
    console.log(err)
})

结果:
在这里插入图片描述

allSettled方法

all方法有一个缺陷:当有其中一个Promise变成reject状态时,新的Promise就会立即变成对应的reject状态。

那么对于resolve的,以及依赖处于pending状态的Promise,我们时获取不到对应的结果;

在ES11(ES2020)中,添加了新的API Promise.allSettled:

改方法会在所有的Promise都有结果(settled),无论时fulfilled,还是rejected时,才会有最终的状态;

并且整个Promise的结果一定时fulfilled的;

// 创建多个Promise
const p1 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('11111')
    },1000)
})

const p2 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        // resolve('222222')
        reject("helloworld") 
    },2000)
})

const p3 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('333333')
    },5000)
})


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

结果:
在这里插入图片描述

可以看出来除了第二个是rejected,其余的都是fulfilled

race方法

如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法:

race是竞赛,竞技的意思,表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果;

// Promise.race
// 创建多个Promise
const p1 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('11111')
    },1000)
})

const p2 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('222222')
        // reject("helloworld")
    },2000)
})

const p3 = new Promise((resolve,reject) =>{
    setTimeout(()=>{
        resolve('333333')
    },5000)
})

// race 只要有一个Promise变成fulfilled 就结束
Promise.race([p1,p2,p3]).then(res=>{
    console.log(res)
}).catch(err=>{
    console.log(err)
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409198.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端面试题 | 什么是回流和重绘?它们的区别是什么?

在了解回流和重绘之前我们可以先简单了解一下浏览器的渲染过程~ 1. 解析获取到的HTML,生成DOM树,解析CSS,生成CSSOM树 2. 将DOM树和CSSOM树进行结合,生成渲染树(render tree) 3.根据生成的渲染树&#xff0…

Vue开发环境安装

目录 Vue概述: Vue特点: Vue官网: 一、node.js安装和配置 1. 下载安装node.js Step1:下载安装包 Step2:安装程序 Step3:查看 问题解决: 解决npm warn config global --global, --local are depr…

Session详解

👑 博主简介:    🥇 Java领域新星创作者    🥇 阿里云开发者社区专家博主、星级博主、技术博主 🤝 交流社区:BoBooY(优质编程学习笔记社区) 前言:上节我们详细讲解了…

华为云从入门到实战 | 云服务概述与华为云搭建Web应用

云计算在快速发展过程中逐渐形成了不同的服务模式(Service Model)。根据云计算最终服务的交付形态主要分为3种类型,软件即服务、平台即服务与基础架构即服务。从根源上来说,云计算的服务模式来源于面向服务的架构SOA(Service-Oriented Architecture)。所谓SOA,就是一种架构设…

npm install或npm i后没有依赖包node_modules?

今天git clone一个项目发现npm i后发现自己的文件下面没有node_modules包,但是有如图提示:但是文件夹下没有任何新增文件 added 1 package in 674ms 随后查看了C:\Users\俊\AppData\Roaming\npm\node_modules 图一: 里面存在今天执行npm i…

微信小程序实训|基于云数据库的语文听写工具

本实训项目结合云开发的云数据库和 “微信同声传译”插件,制作一个可真实运营的小学生语文听写工具,页面效果如图1所示。 ▍图1 “听写小助手”页面 基于云开发的微信小程序具有众多优势,云开发模式真正解放了开发者,使得开发效率…

Vue3全家桶入门 (通过vue-cli脚手架搭建todolist项目环境,深入vue3.0核心知识)

目录 一、todolist项目准备 vue3.0环境搭建🍄 二、todolist基本结构 1. 定义组件🐷 2.实现todolist需要用到的四个组件 🐶 3.ref定义单个数据 🐭 4.reactive定义对象类型的数据🐹 5. 实现todolist每个组件需要…

前端实战【ES6】你会ES6,但是你真的会用吗?

目录🌟前言🌟关于取值🌟关于合并数据🌟关于拼接字符串🌟关于if中判断条件🌟关于列表搜索🌟关于扁平化数组🌟关于获取对象属性值🌟关于添加对象属性🌟关于输入…

vue父子组件传值:父传子、子传父

最近项目中又需要用到父子组件,用了很多次之后对父子组件终于有种从善如流的感觉。会了之后再看自己写的父子组件传值的文章,感觉还是存在很多问题的,问题就不改了,在这篇文章做个总结和纠正吧。 父子组件就是在一个vue文件中引入…

瑞吉外卖项目:编辑员工信息与公共字段自动填充

目录 一. 编辑员工信息 1.1 需求分析 1.2 代码编写 执行流程 后端代码 二. 项目公共字段填充 2.1 问题分析 2.2 代码实现 2.3 功能完善 一. 编辑员工信息 1.1 需求分析 在员工管理列表点击编辑按钮,跳转至编辑页面后,回显员工数据进行修改。 …

前端开发利器--PxCook(像素大厨)

前端开发利器 - - PxCook(像素大厨)1、PxCook简述2、PxCook安装3、PxCook基本操作3.1 通过软件打开设计图3.2 常用快捷键3.3 常用工具3.4 从psd文件中直接获取数据1、PxCook简述 前端开发软件: PS(Photoshop)收费、占…

【SVG】路径<Path>标签详解,一次搞懂所有命令参数

在上一篇文章 什么是SVG&#xff1f;——SVG快速入门 中我对SVG做了基础的介绍&#xff0c;这篇文章将集中讲解<path>标签 本站链接&#xff1a;什么是SVG&#xff1f;——SVG快速入门_gxyzlxf的博客-CSDN博客 稀土掘金链接&#xff1a;什么是SVG&#xff1f;——SVG快…

npm修改默认源(默认镜像)

1 npm修改默认源(默认镜像) 首先如果之前安装过node.js的需要先卸载&#xff0c;删除npm原始默认安装目录&#xff08;在cmd命令面板执行 npm config ls 查看npm默认路径&#xff09; 在cmd命令面板中输入npm config ls 查看npm默认路径 删除操作如下所示&#xff1a; 重新安…

js实现base64,url,blob之间的相互转换

一般来说前端展示图片会通过三种方式&#xff1a; url、base64、blob 1.url: 一般来说&#xff0c;图片的显示还是建议使用url的方式比较好。 let url "http://xxxxxx" 2.base64&#xff1a; 如果图片较大&#xff0c;图片的色彩层次比较丰富&#xff0c;则不适合…

【原创】基于JavaWeb的医院预约挂号系统(医院挂号管理系统毕业设计)

项目介绍&#xff1a;后端采用JspServlet。前端使用的是Layui的一个网站模板。开发一个在线的医院预约挂号系统。从角色的划分&#xff0c;包括用户、医生、管理员。功能模块上包括了公告发布、医院信息查看、医院医生信息查看、预约医生、病例记录、挂号审核、图表统计等模块。…

css常见居中方法总结

最近跟着网上的教程做了几个网页项目&#xff0c;做的过程中关于居中涉及到了好几种方法&#xff0c;遂想将其总结归纳下来&#xff0c;一是理清自己的思路&#xff0c;二是希望能分享给需要帮助的小伙伴们。 话不多数&#xff0c;直奔主题。 本次涉及到的居中方法有七种&…

微信小程序嵌入 H5 页面(web-view)

在开发微信小程序的时候&#xff0c;我们有时候会遇到将 H5 页面嵌入到小程序页面中的情况&#xff1b;微信小程序自带的 web-view 组件相当于 HTML 页面中的 iframe &#xff0c;方便我们在微信小程序中打开一个 H5 页面&#xff1b; 官网描述&#xff1a; 承载网页的容器&a…

微前端(无界)

前言&#xff1a;微前端已经是一个非常成熟的领域了&#xff0c;但开发者不管采用哪个现有方案&#xff0c;在适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户核心诉求都或存在问题&#xff0c;或无法提供支持。本…

vue项目中引入Luckysheet

Luckysheet 介绍 Luckysheet &#xff0c;一款纯前端类似excel的在线表格&#xff0c;功能强大、配置简单、完全开源。 实现功能 格式设置 样式 (修改字体样式&#xff0c;字号&#xff0c;颜色或者其他通用的样式)条件格式 (突出显示所关注的单元格或单元格区域&#xff1…

微信小程序(5)——如何制作好看的表格

✅ 因为 “表格” 在日常统计中无处不在&#xff0c;所以今天来做一做。但是微信小程序不支持 table 标签&#xff0c;我准备用 “上一篇——Flex布局” 学的 flex 来实现一下。 文章目录一、从“html的table”到 “微信小程序的table”二、统一格式的表格三、非统一格式的表格…