No101.精选前端面试题,享受每天的挑战和学习(Promise)

news2024/11/15 22:44:19

在这里插入图片描述

文章目录

    • 1. 解释什么是Promise,并简要说明它的作用和优势。
    • 2. Promise有几种状态?每种状态的含义是什么?
    • 3. 解释Promise链式调用(chaining)的作用和如何实现。
    • 4. 如何捕获和处理Promise链中的错误?
    • 5. 解释Promise.all()和Promise.race()的区别和用途。
    • 6. 如何将回调函数转换为使用Promise的异步操作?
    • 附录:「简历必备」前后端实战项目(推荐:⭐️⭐️⭐️⭐️⭐️)

📈「作者简介」:前端开发工程师 | 蓝桥云课签约作者 | 技术日更博主 | 已过四六级
📚「个人主页」:阿珊和她的猫
🕐「简历必备」前后端实战项目(推荐:⭐️⭐️⭐️⭐️⭐️)

  • Vue.js 和 Egg.js 开发企业级健康管理项目
  • 带你从入门到实战全面掌握 uni-app

1. 解释什么是Promise,并简要说明它的作用和优势。

  • Promise是JavaScript的一种异步编程解决方案,用于处理异步操作。
  • 它提供了更优雅的方式来处理异步操作,使得代码更易读、可维护,并解决了回调地狱问题。
  • Promise具有状态(pending、fulfilled、rejected)和链式调用的特点,使得异步流程控制更加直观和灵活。

Promise是JavaScript中的一种异步编程解决方案,用于处理异步操作。
它是ECMAScript 6引入的一种语言特性。

Promise的主要作用是对异步操作进行更加优雅和可维护的处理。在以往的回调函数模式中,多个异步操作嵌套在一起会形成回调地狱,不易读、不易理解和难以维护。而Promise则提供了一种更具可读性和可组合性的方式来处理异步操作。

Promise的优势体现在以下几个方面:

  1. 可读性和可维护性Promise使用链式调用和.then()方法提供了一种流畅、直观的编程方式,使得代码更易读、易于维护。它可以将异步操作的处理逻辑从回调函数中提取出来,以链式的方式组合多个操作,使得代码结构更加清晰。

  2. 异常处理Promise提供了全局的错误处理机制,可以捕获和处理Promise链中的错误。通过.catch()方法,可以在链式调用中的任意位置捕获错误,并统一处理。这使得错误处理更加方便和一致,避免了传统回调函数中需要繁琐的错误处理。

  3. 异步流程控制Promise可以很好地处理异步操作的顺序和依赖关系。通过.then()方法在多个异步操作之间建立关联,可以实现异步操作的串行、并行和依赖关系,使得异步流程的控制更加灵活和简洁。

  4. 更好的错误传递Promise允许将处理过程中出现的错误通过reject()方法向后传递,直到遇到.catch()或catch方法进行处理。这使得错误可以从异步操作一直传递到Promise链的最后,统一处理错误,提高调试和排查的效率。

综上所述,Promise的作用是提供一种更加优雅和可维护的方式来处理异步操作,从而改善了代码的可读性、可组合性和错误处理能力。通过Promise,可以使异步编程变得更加清晰、简洁和容易管理。

2. Promise有几种状态?每种状态的含义是什么?

  • Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)
  • pending表示Promise的初始化状态,此时既不是成功也不是失败。
  • fulfilled表示异步操作成功完成,Promise的状态从pending变为fulfilled,并返回相应的结果值。
  • rejected表示异步操作失败,Promise的状态从pending变为rejected,并返回相应的错误原因。

Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。

  1. Pending(进行中):初始状态,表示Promise正在进行中,既不是成功也不是失败的状态。

  2. Fulfilled(已完成):表示异步操作成功完成。Promise的状态从pending变为fulfilled,同时传递一个值作为异步操作的结果。

  3. Rejected(已拒绝):表示异步操作失败。Promise的状态从pending变为rejected,同时传递一个原因(错误信息)作为异步操作的失败原因。

下面是一个简单的代码案例来演示Promise的状态变化:

// 创建一个简单的异步函数,用setTimeout模拟异步操作
function asyncFunction() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const randomNum = Math.random();

      if (randomNum > 0.5) {
        resolve(`Async operation completed successfully. Random number: ${randomNum}`);
      } else {
        reject(`Async operation failed. Random number: ${randomNum}`);
      }
    }, 2000);
  });
}

// 调用异步函数
const promise = asyncFunction();

// 检查Promise的状态变化
console.log(promise); // Promise { <pending> }

promise
  .then((result) => {
    console.log(result); // Async operation completed successfully. Random number: 0.7865730020781207
    console.log(promise); // Promise { fulfilled }
  })
  .catch((error) => {
    console.error(error); // Async operation failed. Random number: 0.3090164721127755
    console.log(promise); // Promise { rejected }
  });

在这个例子中,asyncFunction返回一个Promise对象,代表异步操作。当异步操作完成时,调用resolve方法将Promise状态改为fulfilled;当异步操作失败时,调用reject方法将Promise状态改为rejected。通过.then()方法和.catch()方法,可以分别处理异步操作成功和失败的情况。在Promise的不同状态改变时,可以观察到Promise对象的状态变化。

3. 解释Promise链式调用(chaining)的作用和如何实现。

  • Promise链式调用可以在多个异步操作之间构建顺序和依赖关系,使得代码更具可读性和可维护性。
  • 通过返回新的Promise实例,并在每个Promise上调用.then()方法,实现Promise链式调用。
  • 返回的Promise会根据前一个Promise的状态,决定是否立即执行或等待前一个Promise完成后再执行。

Promise链式调用(chaining)可以在多个异步操作之间构建顺序和依赖关系,使得代码更具可读性和可维护性。它允许我们按照一定的顺序执行一系列的异步操作,并且可以根据前一个操作的结果进行下一步操作。

实现Promise链式调用,需要在每个Promise对象上使用.then()方法,返回一个新的Promise对象。通过这种方式,可以在每个.then()方法中依次添加需要执行的异步操作,并且可以根据上一个Promise的状态决定下一步操作的执行。

下面是一个简单的代码案例来演示Promise链式调用的作用和实现:

// 创建一个模拟的异步函数
function asyncFunc1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 1 completed");
    }, 2000);
  });
}

function asyncFunc2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 2 completed");
    }, 2000);
  });
}

function asyncFunc3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 3 completed");
    }, 2000);
  });
}

// 使用Promise链式调用执行异步操作
asyncFunc1()
  .then((result) => {
    console.log(result); // Async function 1 completed
    return asyncFunc2(); // 返回新的Promise对象
  })
  .then((result) => {
    console.log(result); // Async function 2 completed
    return asyncFunc3(); // 返回新的Promise对象
  })
  .then((result) => {
    console.log(result); // Async function 3 completed
  })
  .catch((error) => {
    console.error(error); // 错误处理
  });

在这个例子中,我们定义了三个模拟的异步函数(asyncFunc1、asyncFunc2、asyncFunc3)。通过使用Promise链式调用,在每个.then()方法中依次执行异步操作,并且根据前一个Promise的状态返回一个新的Promise对象,以实现顺序执行和依赖关系。

通过.then()方法,第一个异步函数asyncFunc1被调用,并返回一个新的Promise对象。当asyncFunc1完成后,.then()方法中定义的回调函数将被执行并传递异步操作的结果。然后,我们在第一个回调函数中返回asyncFunc2的Promise对象,并在下一个.then()方法中继续处理。这样,异步操作就可以按照顺序执行,并根据每个操作的结果进行下一步操作。

通过链式调用,我们可以将多个异步操作串联在一起,使代码更加清晰易读,并且可以灵活地处理异步操作的顺序和依赖关系。

4. 如何捕获和处理Promise链中的错误?

  • 可以使用.then()方法的第二个参数或.catch()方法来捕获和处理Promise链中的错误。
  • 在链式调用中,如果前一个Promise发生错误,会跳转到错误处理部分,并返回一个新的被拒绝的Promise。

要捕获和处理Promise链中的错误,可以使用.then()方法的第二个参数或.catch()方法。这样可以在Promise链中的任意位置捕获错误,并统一进行错误处理。

下面是一个代码案例来演示如何捕获和处理Promise链中的错误:

// 创建一个模拟的异步函数
function asyncFunc1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 1 completed");
    }, 2000);
  });
}

function asyncFunc2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Async function 2 failed");
    }, 2000);
  });
}

function asyncFunc3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 3 completed");
    }, 2000);
  });
}

// 使用Promise链式调用执行异步操作,并处理错误
asyncFunc1()
  .then((result) => {
    console.log(result); // Async function 1 completed
    return asyncFunc2();
  })
  .then((result) => {
    console.log(result); // 不会执行到这里
    return asyncFunc3();
  })
  .then((result) => {
    console.log(result); // 不会执行到这里
  })
  .catch((error) => {
    console.error(error); // Async function 2 failed
  });

在这个例子中,我们在asyncFunc2中故意让异步操作失败并通过reject方法传递一个错误信息。当asyncFunc2失败后,该Promise的状态将变为rejected。接着,我们使用.catch()方法来捕获和处理失败的Promise,并输出错误信息。

在Promise链式调用中,如果前一个Promise发生错误,将会跳转到错误处理部分(.catch()方法或.then()方法的第二个参数),并返回一个新的被拒绝的Promise。这样可以确保错误被捕获并进行统一的错误处理,避免错误泄漏和回调地狱。

通过捕获和处理Promise链中的错误,我们可以更好地处理和管理异步操作可能出现的异常情况,提高代码的健壮性和可维护性。

5. 解释Promise.all()和Promise.race()的区别和用途。

  • Promise.all()接收一个Promise数组作为参数,当所有的Promise都成功时,返回一个包含所有结果的Promise;如果任意一个Promise失败,则返回一个被拒绝的Promise。
  • Promise.race()也接收一个Promise数组作为参数,返回一个新的Promise,它将与第一个完成的Promise的状态保持一致,无论是成功还是失败。

下面是Promise.all()和Promise.race()的区别和用途的对比:

Promise.all()Promise.race()
作用并行执行多个异步操作,并等待所有操作完成并行执行多个异步操作,并等待其中任意一个操作完成
参数接受一个Promise数组作为输入接受一个Promise数组作为输入
返回值返回一个Promise对象,当所有Promise都变为fulfilled时,返回的Promise将变为fulfilled,并提供一个包含所有Promise结果的数组返回一个Promise对象,当任意一个Promise变为fulfilled或rejected时,返回的Promise将相应地变为fulfilled或rejected,并提供该Promise的结果
执行顺序Promise.all()会按照Promise数组传入的顺序执行异步操作,并且等待所有操作完成后返回结果Promise.race()会按照Promise数组传入的顺序执行异步操作,但只要有一个操作完成或失败,结果就会立即返回
错误处理如果任何一个Promise被rejected,Promise.all()会立即返回一个被拒绝的Promise,并提供被拒绝的Promise的结果如果任何一个Promise被rejected,Promise.race()会立即返回一个被拒绝的Promise,并提供被拒绝的Promise的结果

下面是一个代码案例来演示Promise.all()和Promise.race()的使用:

// 创建多个异步函数
function asyncFunc1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 1 completed");
    }, 2000);
  });
}

function asyncFunc2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Async function 2 completed");
    }, 1000);
  });
}

function asyncFunc3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Async function 3 failed");
    }, 1500);
  });
}

// 使用Promise.all()
Promise.all([asyncFunc1(), asyncFunc2(), asyncFunc3()])
  .then((results) => {
    console.log(results); // 不会执行到这里
  })
  .catch((error) => {
    console.error(error); // Async function 3 failed
  });

// 使用Promise.race()
Promise.race([asyncFunc1(), asyncFunc2(), asyncFunc3()])
  .then((result) => {
    console.log(result); // Async function 2 completed
  })
  .catch((error) => {
    console.error(error); // 不会执行到这里
  });

在这个例子中,我们创建了三个异步函数asyncFunc1、asyncFunc2和asyncFunc3。使用Promise.all(),我们传入一个包含三个Promise的数组,它们会并行执行,并在所有操作完成后返回一个成功的Promise,并提供包含所有异步操作结果的数组。如果其中任何一个Promise被rejected,返回的Promise会立即变为rejected,并提供被拒绝的Promise的结果。

而使用Promise.race(),同样传入一个包含三个Promise的数组,但只要有一个操作完成(无论成功还是失败),结果就会立即返回,并返回该操作的结果。如果其中任何一个Promise被rejected,返回的Promise也会立即变为rejected,并提供被拒绝的Promise的结果。

通过使用Promise.all()和Promise.race(),我们可以更灵活地处理多个异步操作,并根据需要等待所有操作完成或等待任意一个操作完成。这两种方法在实际的异步编程中非常有用,并提供了更多控制异步操作流程的方式。

6. 如何将回调函数转换为使用Promise的异步操作?

  • 首先,创建一个新的Promise对象,并在异步操作中执行需要转换的回调函数。
  • 在回调函数中,根据异步操作的结果调用resolve()或reject()来改变Promise的状态。
  • 最后,返回这个新的Promise对象,使其成为一个可以进行链式调用的Promise。

要将使用回调函数的异步操作转换为使用Promise的异步操作,可以将回调函数包装在Promise构造函数中,并在适当的时候调用resolve()或reject()来表示异步操作的成功或失败。

下面是一个示例,演示如何将使用回调函数的异步操作转换为使用Promise的异步操作:

// 使用回调函数的异步操作示例
function asyncOperation(callback) {
  setTimeout(() => {
    const randomNumber = Math.random();
    if (randomNumber > 0.5) {
      callback(null, `Async operation completed successfully. Result: ${randomNumber}`);
    } else {
      callback("Async operation failed.", null);
    }
  }, 2000);
}

// 将回调函数转换为使用Promise的异步操作
function asyncOperationWithPromise() {
  return new Promise((resolve, reject) => {
    asyncOperation((error, result) => {
      if (error) {
        reject(error); // 异步操作失败,调用reject
      } else {
        resolve(result); // 异步操作成功,调用resolve
      }
    });
  });
}

// 使用Promise的异步操作
asyncOperationWithPromise()
  .then((result) => {
    console.log(result); // 异步操作完成成功
  })
  .catch((error) => {
    console.error(error); // 异步操作失败
  });

在这个例子中,我们有一个使用回调函数的异步操作asyncOperation。为了将它转换为使用Promise的异步操作,我们创建了一个新的函数asyncOperationWithPromise,它返回一个Promise对象。在Promise的构造函数中,我们调用旧的异步操作,并将回调函数包装在其中。根据异步操作的结果,我们使用resolve()来表示成功并提供结果,而使用reject()来表示失败并提供错误信息。

通过这种方式,我们可以将原来的回调函数风格的异步操作转换为使用Promise的形式。这样可以更好地利用Promise的优势和功能,并与其他Promise相关的操作(如Promise链式调用)配合使用。

附录:「简历必备」前后端实战项目(推荐:⭐️⭐️⭐️⭐️⭐️)

Vue.js 和 Egg.js 开发企业级健康管理项目
带你从入门到实战全面掌握 uni-app

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

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

相关文章

【2023.7.29】本文用于自己写文章时查看Markdown编辑器语法

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

【C语言学习——————动态内存管理】

文章目录 一、什么是动态内存管理二、动态内存函数的介绍 1.malloc函数的介绍2.calloc函数的介绍3.realloc函数的介绍三、free函数的介绍 一.什么是动态内存管理 我们知道数据都是在内存中进行储存的&#xff0c;但是如果我们需要调用内存&#xff0c;我们可以通过定义一个变量…

实现哈希表

一&#xff1a;什么是哈希表&#xff1f; 哈希表是一种常见的数据结构&#xff0c;它通过将键映射到值的方式来存储和组织数据。具体来说&#xff0c;哈希表使用哈希函数将每个键映射到一个索引&#xff08;在数组中的位置&#xff09;&#xff0c;然后将该键值对存储在该索引处…

IOS + Appium自动化教程

前言 项目闲置下来了&#xff0c;终于抽空有时间搞自动化了&#xff0c;看了下网上的教程基本通篇都是android自动化的介绍 &#xff0c;ios自动化方面的内容网上简介的少之可怜。由于本人对ios自动化也是第一次做&#xff0c;甚至对苹果电脑的使用都不太熟悉&#xff0c;花了大…

微信小程序,商城底部工具栏的实现

效果演示&#xff1a; 前提条件&#xff1a; 去阿里云矢量图标&#xff0c;下载8个图标&#xff0c;四个黑&#xff0c;四个红&#xff0c;如图&#xff1a; 新建文件夹icons&#xff0c;把图标放到该文件夹&#xff0c;然后把该文件夹移动到该项目的文件夹里面。如图所示 app…

vue3如何封装接口

&#x1f642;博主&#xff1a;锅盖哒 &#x1f642;文章核心&#xff1a;如何封装接口 目录 前言 1.首先&#xff0c;安装并导入axios库。你可以使用npm或yarn来安装&#xff1a; 2.创建一个api.js文件来管理接口封装&#xff1a; 3.在Vue组件中使用封装的接口&#xff1…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境4

7、使用串口工具 &#xff08;1&#xff09;连接硬件 连接 Type C 线&#xff0c; 一端电脑一端开发板 查看设备是否已经正确识别&#xff1a; 在 Windows 下可以打开设备管理器来查看 如果没有发现设备&#xff0c; 需要确认有没有装驱动以及接触是否良好 &#xff08;2&a…

Ubuntu更改虚拟机网段(改成桥接模式无法连接网络)

因为工作需要&#xff0c;一开始在安装vmware和虚拟机时&#xff0c;是用的Nat网络。 现在需要修改虚拟机网段&#xff0c;把ip设置成和Windows端同一网段&#xff0c;我们就要去使用桥接模式。 环境&#xff1a; Windows10、Ubuntu20.04虚拟机编辑里打开虚拟网络编辑器&#…

安装Harbor

前言 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器&#xff0c;虽然Docker官方也提供了公共的镜像仓库&#xff0c;但是从安全和效率等方面考虑&#xff0c;部署企业内部的私有环境Registry是非常必要的&#xff0c;Harbor和docker中央仓库的关系&#xff0c;…

第四章:Spring上

第四章&#xff1a;Spring上 4.1&#xff1a;Spring简介 Spring概述 官网地址&#xff1a;https://spring.io/。 Spring是最受欢迎的企业级的java应用程序开发框架&#xff0c;数以百万的来自世界各地的开发人员使用Spring框架来创建性能好、易于测试、可重用的代码。Spring框…

【多模态】18、ViLD | 通过对视觉和语言知识蒸馏来实现开集目标检测(ICLR2022)

文章目录 一、背景二、方法2.1 对新类别的定位 Localization2.2 使用 cropped regions 进行开放词汇检测2.3 ViLD 三、效果 论文&#xff1a;Open-vocabulary Object Detection via Vision and Language Knowledge Distillation 代码&#xff1a;https://github.com/tensorflo…

Verilog语法学习——LV10_使用函数实现数据大小端转换

LV10_使用函数实现数据大小端转换 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 描述 在数字芯片设计中&#xff0c;经常把实现特定功能的模块编写成函数&…

HBuilder 编辑器终端窗口无法输入,未响应的解决方案

HBuilder 编辑器终端窗口无法输入&#xff0c;未响应的解决方案 一、找到 HBuilder 安装目录 找到 main.js HBuilderX - plugins - builtincef3terminal - script - main.js 二、编辑 main.js 将 main.js 文件中的 powershell.exe 和 cmd.exe 路径都改为绝对路径 C:/Windows…

【渗透测试】漏洞扫描AWVS安装使用教程,三分钟手把手教会,非常简单

一、AWS简介 Acunetix Web Vulnerability Scanner(简称AWVS)是一个自动化的Web漏洞扫描工具&#xff0c;它可以扫描任何通过Web浏览器访问和遵循HITP/HTTPS规则的Web站点。 AWVS原理是基于漏洞匹配方法&#xff0c;通过网络爬虫测试你的网站安全&#xff0c;检测流行安全AWVS可…

Hadoop学习日记-YARN组件

YARN(Yet Another Resource Negotiator)作为一种新的Hadoop资源管理器&#xff0c;是另一种资源协调者。 YARN是一个通用的资源管理系统和调度平台&#xff0c;可为上层应用提供统一的资源管理和调度 YARN架构图 YARN3大组件&#xff1a; &#xff08;物理层面&#xff09…

Spring学习笔记,包含Spring IOC、AOP基本原理、Bean管理、Spring 事务等等

&#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏. 文章目录 Spring 基础笔记1、控制反转 (IOC)1.1、IOC 底层原理1.2、IOC 之Bean管理 ( XML )1.3、IOC 之Bean管理 (FactoryBean)1.4、Bean的作用域1.5、Bean的生命周期1.6、Bean的自动装配1.7、I…

SFP6002-ASEMI代理海矽美快恢复二极管参数、尺寸、规格

编辑&#xff1a;ll SFP6002-ASEMI代理海矽美快恢复二极管参数、尺寸、规格 型号&#xff1a;SFP6002 品牌&#xff1a;ASEMI 封装&#xff1a;TO-247AB 恢复时间&#xff1a;30ns 正向电流&#xff1a;60A 反向耐压&#xff1a;200V 芯片大小&#xff1a;102MIL*2 芯…

几个影响 cpu cache 性能因素及 cache 测试工具介绍

》内核新视界文章汇总《 文章目录 1 cache 性能及影响因素1.1 内存访问和性能比较1.2 cache line 对性能的影响1.3 L1 和 L2 缓存大小1.4 指令集并行性对 cache 性能的影响1.5 缓存关联性对 cache 的影响1.6 错误的 cacheline 共享 (缓存一致性)1.7 硬件设计 2 cpu cache benc…

【EI/SCOPUS会议征稿】第四届机器学习与计算机应用国际学术会议(ICMLCA 2023)

ICMLCA 2023 第四届机器学习与计算机应用国际学术会议 2023 4th International Conference on Machine Learning and Computer Application 第四届机器学习与计算机应用国际学术会议(ICMLCA 2023)定于2023年10月27-29日在中国杭州隆重举行。本届会议将主要关注机器学习和计算…

rk3568 Debian11 如何打开热点

思路&#xff1a;1. 下载必要工具&#xff08;hostapt、dnsmasq&#xff09;2. 配置网络&#xff08;无线网卡配置静态IP&#xff09;3. 配置hostapt配置文件4. 配置DHCP服务5. 启动服务&#xff08;hostapd/dnsmasq/network&#xff09;6. IP转发&#xff08;这一步决定了是否…