学会Promise,看这里!!!

前言

众所周知,在JavaScript的世界中,代码都是单线程执行的。由于这个原因,JavaScript中的耗时操作,如网络操作、浏览器事件等,都需要异步执行。这也导致在JavaScript中异步操作是非常频繁且常见的。

异步:在执行某些耗时、不会立即返回结果的操作时,不会阻塞后面的操作,一旦该耗时操作完成时,立即通知需要调用其结果的函数来做后续处理。

而这种通知需要调用其结果的函数来做后续处理,一般都是通过回调的方式实现的。但是为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,就会出现”回调地狱“。比如说你要把一个函数 A作为回调函数,但是该函数又接受一个函数B作为参数,甚至B还接受C作为参数使用,就这样层层嵌套,人称之为回调地狱,代码阅读性非常差。比如:

var sayhello = function (name, callback) {
  setTimeout(function () {
    console.log(name);
    callback();
  }, 1000);
}

sayhello("first", function () {
  sayhello("second", function () {
    sayhello("third", function () {
      console.log("end");
    });
  });
});

//输出: first second third  end

而Promise作为一种可以优雅的解决这种”回调地狱“问题的方案,在实际开发中大面积使用,具有非常不错的效果。平时开发中,自己也经常看到这种情况,但是每次都是按照模板套路去编写业务代码,至于Promise是怎么使用的,根本没有学习总结过,导致自己总是一头雾水。这次,就认真的总结一下,同样的,只看样式,不究原理。待日后武义精益了,再来深挖掘。

Promise简介

Promise是异步编程的一种解决方案,是一个对象,可以获取异步操作的消息,大大改善了异步编程的困难,避免了回调地狱,比传统的解决方案回调函数和事件更合理和更强大。

从语法上讲,Promise是一个对象,它可以获取异步操作的消息。提供了一个统一的API,各种异步操作都可以用同样的方法进行处理。

首先了解下Promise的几个要点知识:

  1. 语法上,promise是一个构造函数;功能上,promise对象用来封装一个异步操作并获取执行的结果;
  2. 它有三种状态,pending(打包中,创建promise对象后的状态)、resolved(成功)、rejected(失败);
  3. 一个promise对象只能改变一次状态,成功或者失败后都会返回结果数据;
  4. 成功的结果数据一般称为value,失败的结果数据为reason。

Promise的实例有两个过程:

  1. pending > fulfilled :Resolved
  2. pending > rejected :Rejected

Promise基本用法

创建Promise对象

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolvereject

Promise创建时,会传给promise一个称为excutor执行器的函数。这个excutor我们可以理解为生产者的生产过程函数。这个函数含有两个参数resolve和reject,这俩参数也同样是函数,用来传递异步操作的结果。

let promise = new Promise(function(resolve, reject) {
  // executor 
})

重点说明:

  1. 在Promise对象创建时,excutor会立即执行;
  2. 在resolve和reject是JS引擎自动创建的函数,我们无需自己创建,只需将其作为参数传入就好。

then()用法

Promise 实例生成以后,可以用 then 为实例添加状态改变时的回调函数。then方法可以接收两个回调函数作为参数,第一个回调函数是Promise对象的状态改变为resoved的调用,第二个回调函数是Promise对象的状态变为rejected的调用。其中第二个参数可以省略。

function getData() {
    return new Promise(function(resolve, reject) {
        var obj = {num : 0};
        setTimeout(function(){ // 模拟异步请求
            obj.num = Math.random();
            resolve(obj);
        }, 1000);
    });
}

getData().then(function(obj){
    console.log(obj.num);
});

getData函数返回一个promise实例,使用then为它指定一个Resolved状态的回调函数,异步请求中传给resolve的值,将作为回调函数中的参数。当异步请求成功之后,回调函数变会执行输出对应的值。

假设异步请求失败了怎么办? then其实还可以指定第二个可选的参数,即Rejected状态的回调函数。

getData().then(function(obj){
    console.log(obj.num);
}, function(error){
    console.log(error);
});

catch()用法

在上述例子中,异步请求成功后,第一个回调函数会执行,如果失败了,第二个回调函数便会执行。

其实我们还可以使用catch指定错误时的回调,catch调用其实等同于使用then(undefined, function)。上述代码和以下代码是同样的效果。

getData().then(function(obj){
    console.log(obj.num);
}).catch(e){
    console.log(e);
}

all()用法

all方法可以完成并进行任务,它接收的是一个数组,数组的每一项都是Promise对象。当数组中所有的Promise状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected。那么all方法的状态就会变成rejected。

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.all([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 输出 [1, 2, 3]
});

race()用法

race方法和all一样,接收的参数是一个每项都是Promise的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。

race的实际作用:当要做一件事,超过长时间就不做了,可以用这个方法来解决。

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.race([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 输出 1
});

finally()用法

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。finally方法的回调函数不接受任何参数,这意味着没有办法知道前面的Promise状态到底是fulfilled还是rejected。

总结

由于自己对这个知识点掌握的少,所以这篇文章总结的很基础,希望对入门的选手有一个帮助。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

B端能用就行,颜值无所谓?你现在还敢说吗,马上轮到工业HMI

在当前的商业环境下,用户体验和界面设计的重要性越来越受到重视,即使是B端用户也希望能够使用界面美观、易于操作的工业HMI系统。 漂亮的设计不仅可以提高用户的工作效率和满意度,还可以提升产品的竞争力和市场份额。因此,即使是…

Java 面试题之框架

1. Spring 是什么 Sping 是包含了众多工具方法的 IOC 容器,IOC是控制反转,说的是对象的创建和销毁的权利都交给 Spring 来管理了, 它本身又具备了存储对象和获取对象的能力. 。 容器:字面意思,用来容纳某种物品的装置。 比如 L…

力扣题目训练(22)

2024年2月15日力扣题目训练 2024年2月15日力扣题目训练563. 二叉树的坡度637. 二叉树的层平均值643. 子数组最大平均数 I304. 二维区域和检索 - 矩阵不可变154. 寻找旋转排序数组中的最小值 II 2024年2月15日力扣题目训练 2024年2月15日第二十二天编程训练,今天主要…

高并发缓存策略大揭秘:面试必备的缓存更新模式解析

在高并发场景中,缓存能抵挡大量数据库查询,减少数据库压力,对于缓存更新通常有以下几种模式可以选择: cache aside read/write through write behind caching cache aside模式 Cache-aside模式是一种常用的用于管理缓存的模…

【linux深入剖析】操作系统与用户之间的接口:自定义简易shell制作全过程

🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 1.shell2.自定义shell的准…

如何遍历map

小王学习录 前言遍历map集合1. 使用for-each循环遍历 entrySet()2. 使用迭代器遍历 entrySet()3. 通过 keySet() 遍历4. 使用迭代器遍历 keySet()5. 仅遍历 values() 如果只关心map中的值而不关心键,可以遍历 values():6. 使用流(Streams)进行遍历 总结 …

typeorm导致nestjs通过@Query接收的参数为undefined

依赖版本如下,发现引入typeorm后导致接收不到Query参数,解决办法是将 TypeOrmModule导入语句放到前面就可以了

MT3004·找四边形

题目&#xff1a; 样例输入 4 12 1 2 1 3 1 4 2 1 2 3 2 4 3 1 3 2 3 4 4 1 4 2 4 3 样例输出 12 数据范围 算法设计 涉及的算法 枚举和图论基础 采用邻接矩阵g[N]来存储图&#xff0c;其中vector<ll> g[N]是建立了一个二维的vector 来用sum记录每个点 i 到达点 j…

java集合框架——Map集合概述

前言&#xff1a; 之前接触了单列合集&#xff0c;现在又接触了双列合集。整理下心得&#xff0c;打好基础&#xff0c;daydayup&#xff01;&#xff01; Map集合 Map集合称为双列集合&#xff0c;也被称为“键值对集合”。格式&#xff1a;{key1value1,key2value2...}&#…

网络学习:邻居发现协议NDP

目录 前言&#xff1a; 一、报文内容 二、地址解析----NS/NA 目标的被请求组播IP地址 邻居不可达性检测&#xff1a; 重复地址检测 路由器发现 地址自动配置 默认路由器优先级和路由信息发现 重定向 前言&#xff1a; 邻居发现协议NDP&#xff08;Neighbor Discovery…

MySQL数据库实现增删改查基础操作

准备工作 安装mysql8.0 (安装时一定要记住用户名和密码)安装数据库可视化视图工具Navicat 请注意⚠️⚠️⚠️⚠️ a. 编程类所有软件不要安装在中文目录下 b. Navicat破解版下载安装教程&#xff1a;&#xff08;由于文章审核提示版权问题&#xff0c;链接不方便给出&#xff…

虚拟内存相关知识汇总(程序重定位)

前置知识&#xff1a; Windows的内存可以被分为两个层面&#xff1a;物理内存和虚拟内存。其中&#xff0c;物理内存非常复杂&#xff0c;需要进入到Windows内核级别ring0才能看到。通常在用户模式下&#xff0c;用调试器看到的内存地址都是虚拟地址。 1.虚拟内存的定义 虚拟…

PCIE问题定位000:PCIe需要的定位手段

1、PCIe debug环境说明 本文将以PCIe EP用户逻辑举例&#xff0c;描述PCIe可以添加哪些定位手段。 如图所示&#xff0c;PCIe IP作为endpoint与RC对接&#xff0c;用户实现了应用逻辑&#xff0c;与PCIe IP进行交互&#xff0c;交互信号中data格式为TLP报文格式&#xff0c;且…

Linux_基础指令(一)

目录 1、ls指令 1.1 ls -l 1.2 ls -a 1.3 ls -i 2、pwd指令 3、cd指令 3.1 路径的概念 3.1.1 绝对路径 3.1.2 相对路径 3.2 cd ~ 3.3 cd - 4、touch指令 5、mkdir指令 6、删除系列的指指令 6.1 rmdir 6.2 rm 7、man指令 8、cp指令 9、move指令 结…

【智能算法】斑鬣狗优化算法(SHO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过。 3.代码实现4.参考文献 1.背景 2017年&#xff0c;Dhiman等人受到斑鬣狗自然狩猎行为启发&#xff0c;提出了斑鬣狗优化算法(Spotted Hyena Optimizer, SHO)。 2.算法原理 2.1算法思想 SHO将斑鬣狗狩猎行为分为围捕-狩猎-进攻三…

多线程JUC 第2季 wait和notify唤醒机制

一 wait和notify的区别与相同 1.1 wait和notify的作用 1) 使用wait()、notify()和notifyAII()时需要先对调用对象加锁。否则直接调用的话会抛出 IllegalMonitorStateExceptiona。 2) 调用wait()方法后&#xff0c;线程状态。由RUNNING变为WAITING&#xff0c;并将当前线程放置…

wordpress子比主题7.6美化插件及新手零基础搭建教程源码下载

版权申请&#xff1a;本文A5资源网原创&#xff0c;经原创作者允许转载许可声明。下载地址http://a5.org.cn/a5_ziyuan/39172.html 本源码由网友在某宝二十几元购买&#xff0c;现分享给大家。下图为源码文件及演示图&#xff0c;安装教程比较详细新手零基础就可搭建 子比主…

NeRF——基于神经辐射场的三维场景重建和理解

概述 三维重建是一种将物理世界中的实体转换为数字模型的计算机技术。其基本概念是通过对物理世界中的物体或场景进行扫描或拍摄&#xff0c;并使用计算机算法将其转换为三维数字模型。抽象意义上的三维模型指的是&#xff1a;形状和外观的组合&#xff0c;并且可以渲染成不同…

【Redis知识点总结】(四)——如何保证缓存与数据库中的数据一致性

Redis知识点总结&#xff08;四&#xff09;——如何保证缓存与数据库中的数据一致性 更新缓存删除缓存先删除缓存后更新数据库先更新数据库后删除缓存 使用canal总结 面试会经常遇到这种问题&#xff1a;你们如何保证缓存与数据库中的数据一致性&#xff1f;或者是&#xff1a…

小白必看的Python基础之函数篇

函数最重要的目的是方便我们重复使用相同的一段程序。 将一些操作隶属于一个函数&#xff0c;以后你想实现相同的操作的时候&#xff0c;只用调用函数名就可以&#xff0c;而不需要重复敲所有的语句。 函数的定义 首先&#xff0c;我们要定义一个函数, 以说明这个函数的功能…