常见 Promise 面试问题

2023-05-16

前端面试过程中,基本都会问到 Promise,如果你足够幸运,面试官问的比较浅,仅仅问 Promise 的使用方式,那么恭喜你。事实上,大多数人并没有那么幸运。所以,我们要准备好九浅一深的知识。

常见的promise面试问题 

我们看一些 Promise 的常见面试问法,由浅至深。

  1. 了解 Promise 吗?
  2. Promise 解决的痛点是什么?
  3. Promise 解决的痛点还有其他方法可以解决吗?如果有,请列举。
  4. Promise 如何使用?
  5. Promise 常用的方法有哪些?它们的作用是什么?
  6. Promise 在事件循环中的执行过程是怎样的?
  7. Promise 的业界实现都有哪些?
  8. 能不能手写一个 Promise 的 polyfill。

这些问题,如果你都能 hold 住,那么面试官基本认可你了。带着上面这些问题,我们往下看。

Promise 出现的原因(对promise的了解)

在 Promise 出现以前,我们处理异步网络请求,大概是这样:

// 一个请求 看起来很不错
请求1(function(请求结果1){
    处理请求结果1
})

//两个请求 也不复杂可以接受
请求1(function(请求结果1){
    请求2(function(请求结果2){
        处理请求结果2
    })
})

// 多个请求 看起来头都大了!这个你还能忍受吗?
请求(function(请求结果1){
    请求2(function(请求结果2){
        请求3(function(请求结果3){
            请求4(function(请求结果4){
                请求5(function(请求结果5){
                    请求6(function(请求结果6){
                        ...
                    })
                })
            })
        })
    })
})

当我们需求是永无止境的时候,就傻眼了,传说中的 回调地狱 现身了。

更糟糕的是,我们基本上还要对每次请求的结果进行一些处理,代码会更加臃肿,在一个团队中,代码 review 以及后续的维护将会是一个很痛苦的过程。

回调地狱带来的负面作用有以下几点:

  • 代码臃肿。
  • 可读性差。
  • 耦合度过高,可维护性差。
  • 代码复用性差。
  • 容易滋生 bug。
  • 只能在回调里处理异常。

出现了问题,自然就会有人去想办法。这时,就有人思考了,能不能用一种更加友好的代码组织方式,解决异步嵌套的问题。

let 请求结果1 = 请求1();
let 请求结果2 = 请求2(请求结果1); 
let 请求结果3 = 请求3(请求结果2); 
let 请求结果4 = 请求2(请求结果3); 
let 请求结果5 = 请求3(请求结果4); 

类似上面这种同步的写法。 于是 Promise 规范诞生了。

什么是 Promise

Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。现已被 ES6 纳入进规范中。

代码书写比较

还是使用上面的多个网络请求例子,我们看下 Promise 的常规写法:

new Promise(请求1)
    .then(请求2(请求结果1))
    .then(请求3(请求结果2))
    .then(请求4(请求结果3))
    .then(请求5(请求结果4))
    .catch(处理异常(异常信息))
复制代码

比较一下这种写法和上面的回调式的写法。我们不难发现,Promise 的写法更为直观,并且能够在外层捕获异步函数的异常信息。

API

Promise 的常用 API 如下:

  • Promise.resolve(value)

类方法,该方法返回一个以 value 值解析后的 Promise 对象 1、如果这个值是个 thenable(即带有 then 方法),返回的 Promise 对象会“跟随”这个 thenable 的对象,采用它的最终状态(指 resolved/rejected/pending/settled)
2、如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。
3、其他情况以该值为成功状态返回一个 Promise 对象。

上面是 resolve 方法的解释,传入不同类型的 value 值,返回结果也有区别。这个 API 比较重要,建议大家通过练习一些小例子,并且配合上面的解释来熟悉它。如下几个小例子:

//如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。  
function fn(resolve){
    setTimeout(function(){
        resolve(123);
    },3000);
}
let p0 = new Promise(fn);
let p1 = Promise.resolve(p0);
// 返回为true,返回的 Promise 即是 入参的 Promise 对象。
console.log(p0 === p1);
复制代码

传入 thenable 对象,返回 Promise 对象跟随 thenable 对象的最终状态。

ES6 Promises 里提到了 Thenable 这个概念,简单来说它就是一个非常类似 Promise 的东西。最简单的例子就是 jQuery.ajax,它的返回值就是 thenable 对象。但是要谨记,并不是只要实现了 then 方法就一定能作为 Promise 对象来使用。

//如果传入的 value 本身就是 thenable 对象,返回的 promise 对象会跟随 thenable 对象的状态。
let promise = Promise.resolve($.ajax('/test/test.json'));// => promise对象
promise.then(function(value){
   console.log(value);
});
复制代码

返回一个状态已变成 resolved 的 Promise 对象。

let p1 = Promise.resolve(123); 
//打印p1 可以看到p1是一个状态置为resolved的Promise对象
console.log(p1)
复制代码
  • Promise.reject

类方法,且与 resolve 唯一的不同是,返回的 promise 对象的状态为 rejected。

  • Promise.prototype.then

实例方法,为 Promise 注册回调函数,函数形式:fn(vlaue){},value 是上一个任务的返回结果,then 中的函数一定要 return 一个结果或者一个新的 Promise 对象,才可以让之后的then 回调接收。

  • Promise.prototype.catch

实例方法,捕获异常,函数形式:fn(err){}, err 是 catch 注册 之前的回调抛出的异常信息。

  • Promise.race

类方法,多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败。 。

  • Promise.all

类方法,多个 Promise 任务同时执行。
如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。

  • ...

以上几种便是 Promise 的常用 API,掌握了这些,我们便可以熟练使用 Promise了。

一定要多练习,熟练掌握,否则一知半解的理解在面试时捉襟见肘。

如何理解 Promise

为了便于理解 Promise,大家除了要多加练习以外,最好的方式是能够将Promise的机制与现实生活中的例子联系起来,这样才能真正得到消化。

我们可以把 Promise 比作一个保姆,家里的一连串的事情,你只需要吩咐给他,他就能帮你做,你就可以去做其他事情了。
比如,作为一家之主的我,某一天要出门办事,但是我还要买菜做饭送到老婆单位(请理解我在家里的地位。。)

出门办的事情很重要,买菜做饭也重要。。但我自己只能做一件事。

这时我就可以把买菜做饭的事情交给保姆,我会告诉她:

  • 你先去超市买菜。
  • 用超市买回来的菜做饭。
  • 将做好的饭菜送到老婆单位。
  • 送到单位后打电话告诉我。

我们知道,上面三步都是需要消耗时间的,我们可以理解为三个异步任务。利用 Promise 的写法来书写这个操作:

function 买菜(resolve,reject) {
    setTimeout(function(){
        resolve(['西红柿'、'鸡蛋'、'油菜']);
    },3000)
}
function 做饭(resolve, reject){
    setTimeout(function(){
        //对做好的饭进行下一步处理。
        resolve ({
            主食: '米饭',
            菜: ['西红柿炒鸡蛋'、'清炒油菜']
        })
    },3000) 
}
function 送饭(resolve,reject){
    //对送饭的结果进行下一步处理
    resolve('老婆的么么哒');
}
function 电话通知我(){
    //电话通知我后的下一步处理
    给保姆加100块钱奖金;
}
复制代码

好了,现在我整理好了四个任务,这时我需要告诉保姆,让他按照这个任务列表去做。这个过程是必不可少的,因为如果不告诉保姆,保姆不知道需要做这些事情。。(我这个保姆比较懒)

// 告诉保姆帮我做几件连贯的事情,先去超市买菜
new Promise(买菜)
//用买好的菜做饭
.then((买好的菜)=>{
    return new Promise(做饭);
})
//把做好的饭送到老婆公司
.then((做好的饭)=>{
    return new Promise(送饭);
})
//送完饭后打电话通知我
.then((送饭结果)=>{
    电话通知我();
})
复制代码

至此,我通知了保姆要做这些事情,然后我就可以放心地去办我的事情。

请一定要谨记:如果我们的后续任务是异步任务的话,必须return 一个 新的 promise 对象。
如果后续任务是同步任务,只需 return 一个结果即可。
我们上面举的例子,除了电话通知我是一个同步任务,其余的都是异步任务,异步任务 return 的是 promise对象。

除此之外,一定谨记,一个 Promise 对象有三个状态,并且状态一旦改变,便不能再被更改为其他状态。

  • pending,异步任务正在进行。
  • resolved (也可以叫fulfilled),异步任务执行成功。
  • rejected,异步任务执行失败。

Promise的使用总结。

Promise 这么多概念,初学者很难一下子消化掉,那么我们可以采取强制记忆法,强迫自己去记住使用过程。

  • 首先初始化一个 Promise 对象,可以通过两种方式创建, 这两种方式都会返回一个 Promise 对象。

    • 1、new Promise(fn)
    • 2、Promise.resolve(fn)
  • 然后调用上一步返回的 promise 对象的 then 方法,注册回调函数。

    • then 中的回调函数可以有一个参数,也可以不带参数。如果 then 中的回调函数依赖上一步的返回结果,那么要带上参数。比如
        new Promise(fn)
        .then(fn1(value){
            //处理value
        })
    复制代码
  • 最后注册 catch 异常处理函数,处理前面回调中可能抛出的异常。

通常按照这三个步骤,你就能够应对绝大部分的异步处理场景。用熟之后,再去研究 Promise 各个函数更深层次的原理以及使用方式即可。

看到这里之后,我们便能回答上面的问题 4 和问题 5了。

Promsie 与事件循环

Promise在初始化时,传入的函数是同步执行的,然后注册 then 回调。注册完之后,继续往下执行同步代码,在这之前,then 中回调不会执行。同步代码块执行完毕后,才会在事件循环中检测是否有可用的 promise 回调,如果有,那么执行,如果没有,继续下一个事件循环。

关于 Promise 在事件循环中还有一个 微任务的概念(microtask),感兴趣的话可以看我这篇关于nodejs 时间循环的文章 剖析nodejs的事件循环,虽然和浏览器端有些不同,但是Promise 微任务的执行时机相差不大。

Promise 的升级

ES6 出现了 generator 以及 async/await 语法,使异步处理更加接近同步代码写法,可读性更好,同时异常捕获和同步代码的书写趋于一致。上面的列子可以写成这样:

(async ()=>{
    let 蔬菜 = await 买菜();
    let 饭菜 = await 做饭(蔬菜);
    let 送饭结果 = await 送饭(饭菜);
    let 通知结果 = await 通知我(送饭结果);
})();
复制代码

是不是更清晰了有没有。需要记住的是,async/await也是基于 Promise 实现的,所以,我们仍然有必要深入理解 Promise 的用法。

结语

相信各位看官看到这里也累了,同时限于篇幅,本文不再对手动实现 Promise 进行讲解了,留待下一篇文章~

上面的内容希望读者多做练习,吃透 Promise 的使用与原理,让面试更加从容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见 Promise 面试问题 的相关文章

  • 在 Promise 链上使用 setTimeout

    在这里 我试图围绕承诺进行思考 在第一个请求中 我获取一组链接 在下一个请求中 我获取第一个链接的内容 但是我想在返回下一个承诺对象之前进行延迟 所以我使用setTimeout就可以了 但它给了我以下 JSON 错误 without set
  • ES6 箭头函数和 Promise Chaining 精简语法解释

    在下面的代码块中 有人可以提供压缩警报语句语法的链接或解释吗 我理解前面的扩展等效代码已被注释掉并包含消息参数 但是 我找不到省略消息参数的语法参考 let timeoutPromise new Promise resolve reject
  • 异步加载车把模板

    我正在尝试编写一个函数 该函数将为我提供一个已编译的车把模板 我将所有模板都放在单独的文件中 使用 ajax 调用来获取模板并编译它以供使用 但我需要使用承诺 以便我可以实际使用它 function getTemplate name get
  • 使用 Promise 时保留变量的最佳实践[重复]

    这个问题在这里已经有答案了 我是 Promises 的新手 我想知道在沿着链向下的同时保留变量的最佳实践是什么 通过 Promise 连接到 MongoDB 非常简单 connectToMongoDB data done function
  • 嵌套 Javascript Promise - 从 firestore 获取数据

    在过去的三天里 我一直被这个错误困扰 我已经尝试了几乎所有的方法 尝试以 1000 种方式构建承诺 但似乎没有任何效果 也许我正在失去 大局 所以希望新的眼睛能有所帮助 谢谢阅读 我有一个在 Firebase Cloud Functions
  • NodeJS 获取承诺回调挂起

    我有这个代码 fetch url then response gt const json response json console log simplest possible fetch json json where 在控制台中我得到
  • 不解决或拒绝承诺是否安全

    想象一下一个 Web 应用程序 其路由需要在继续之前检查是否允许用户访问给定资源 已通过身份验证 检查依赖于数据库调用 在每条路线中 我可能有 authorizeOwnership req res then function do stuf
  • 同步迭代 javascript 对象

    我有一个像这样的对象 let myObject db1 db1 file1Id db1 file2Id db 1file3Id db2 db2 file1Id db2 file2Id 我遍历这个对象并在每次迭代中 我连接到数据库 检索文件
  • Angular 模板调用函数可以返回 Promise

    Angular 的 q 文档 http docs angularjs org api ng 24q说 q 承诺被模板引擎以角度方式识别 这意味着在模板中 您可以将附加到范围的承诺视为结果值 Angular 的视图模板还允许您计算表达式 这意
  • MediaStream 未处理的承诺拒绝:[object DOMError](在 Safari 11 中)

    在下面初始化 WebRTC 的方法中 我在 Safari Tech Preview 11 中遇到了未处理的承诺拒绝 具体来说 当我分配MediaStream像这样的视频元素 video srcObject event stream 堆栈跟踪
  • 使用 Promise 语法编写同步代码有什么好处吗?

    有同步承诺这样的概念吗 使用 Promise 语法编写同步代码有什么好处吗 try foo bar a b bam catch e handleError e 可以写成类似的东西 但使用同步版本then foo then bar bind
  • 使用 Bluebird.js 和 Twitter 流的 Promise 和流

    我对 Promises 和 Node 非常陌生 并且对在流中使用 Promise 感到好奇 我可以承诺直播吗 使用 Bluebirdjs 和 Twit 模块 我有以下内容 var Twit require twit var Promise
  • 关于 Node.js Promise then 和 return?

    我对承诺感到困惑 I use 那么就答应没有返回像这样 new Promise resolve reject gt resolve 1 then v1 gt console log v1 new Promise resolve reject
  • 使用 Promise 对 Google 表格进行多次查询

    我是一名初学者编码器 需要一些帮助来加快我的 Google 表格查询速度 我环顾四周 找不到解决方案 我正在尝试快速对 Google 表格运行 25 个查询 这就是我的尝试方式 对 Google 工作表运行查询 将结果推送到数组 运行不同的
  • Javascript ES6 承诺支持“done”api 吗?

    例如 p new Promise function resolve reject throw err p done 在大多数 Promise Polyfill 库中 done 会抛出错误 并且当前执行将退出 但如果我们使用p then 什么
  • Chrome 扩展同步调用 - 仅在窗口关闭后创建窗口

    我有这个代码 function voteNewWindow mailNum chrome windows create url http www google com incognito true function window conso
  • Promise.any() 和 Promise.race() 有什么区别

    有什么区别Promise any and Promise race 以及它们如何以不同的方式使用 From MDN https developer mozilla org en US docs Web JavaScript Referenc
  • Javascript 然后没有承诺返回值

    也许我没有正确谷歌搜索 不带参数的 then 函数不会阻塞吗 例如 你有一个承诺 someFunc gt return new Promise res rej gt somethingAsync input then val gt res
  • 在 Angular 中,promise 的 error 和 catch 函数在概念上有什么区别?

    我终于得到了 Angular Promise 错误处理 但这对我来说是违反直觉的 我期望错误由失败回调来处理 但我不得不使用 catch 我在概念上不太明白为什么执行 catch 而不是失败回调 我所期望的 SomeAsyncService
  • 为什么Promise中的代码会同步执行? [复制]

    这个问题在这里已经有答案了 在我的项目中 我有一个很长时间运行的操作 所以我决定将其放入Promise因为我认为这样我就可以在里面的代码继续执行其他操作Promise正在跑步 调试的时候发现外面的代码Promise仅当里面的代码执行Prom

随机推荐

  • react 脚手架 run eject 之后 打包生成map文件 体积过大

    react 脚手架 打包生成map文件 体积过大 写在前面 xff0c map文件是帮助我们查看报错的位置的 map文件由devtool属性控制 xff0c 然后全文搜索devtool 发现在webpack config js文件 150
  • 机器学习实战分享:用 Python 进行信用卡欺诈检测

    本文旨在使用 XGBoost 随机森林 KNN 逻辑回归 SVM 和决策树解决分类问题 xff0c 内容较长 xff0c 建议收藏 关注 点赞 案例简介 假设你受雇于帮助一家信用卡公司检测潜在的欺诈案件 xff0c 你的工作是确保客户不会因
  • 麻将算法之 ------ 胡牌算法

    麻将数据牌集合 span class hljs keyword private span span class hljs keyword int span cardDataArray 61 span class hljs number 0x
  • ROS+Bebop2无人机+YOLO算法实现无人机视角的实时目标检测

    前言 xff1a 很久之前 xff0c 用TK1玩过一段时间的ROS xff0c 再加上各种硬件 Arduino 激光雷达 编码电机等 xff0c 模仿着做过Turtlebot小车 xff0c 实现了部分Turtlebot部分的功能 xff
  • 享年94岁,图灵奖得主、计算复杂性理论先驱Juris Hartmanis逝世

    7月29日 xff0c 1993年图灵奖得主 计算复杂性理论创始人之一Juris Hartmanis去世 xff0c 享年94岁 从物理学到数学 xff0c 最终深耕计算机科学领域 Hartmanis于1928年7月5日出生于拉脱维亚 xf
  • DSST目标跟踪算法

    DSST算法也是基于KCF算法改的较好的一种 DSST xff08 Accurate Scale Estimation for RobustVisual Tracking xff09 是2015年BMVC xff08 InProceedin
  • 解决workman部署到Linux环境无法启动和连接的问题(结合TP6框架)

    0 检查Linux是否满足workman的环境要求 span class token function curl span span class token parameter variable Ss span www workerman
  • 按照 STAR 法则介绍自己做过的项目

    大家好啊 xff0c 我是大田 介绍项目注意两点 xff1a 1 自己真的做过 2 逻辑表达能力 为什么推荐你用 STAR 法则说呢 xff1f STAR 法则是结构化面试中非常重要的理论 面试官通过这样的描述全面了解你的测试知识 经验 技
  • 汇总最近遇到的 Linux 面试题

    大家好啊 xff0c 我是大田 今天汇总最近小伙伴遇到的 Linux 面试题 1 你之前在公司使 linux 命令做什么 xff1f 搭建测试环境 查看后台 志 2 在之前公司 xff0c 测试环境使 的是哪个 linux 版本 xff1f
  • vio

    VIO概述 0 IMU与视觉进行比较 IMU视觉惯性测量单元利用图像的VIO六自由度IMU xff0c 陀螺仪测量角加速度 加速度计测量加速度利用图像通过特征 像素 xff08 直接法 xff09 进行位姿估计高频 gt 61 100hz
  • ZUPT的相关初步理解

    参考至https zhuanlan zhihu com p 115529319 零速修正 Zero Velocity Update ZUPT 即 xff0c 当载体处于静止状态时 xff0c 载体此时的速度为零 xff0c 利用载体中的惯性
  • 误差状态方程与雅可比矩阵

    误差状态方程 在惯性的优化中包括p v q ba bg 外参等等优化变量 预积分量由陀螺 加计的示数得到 xff0c 以及陀螺 加计的白噪声 偏置 可以先将白噪声从预积分量中剥离出来 xff0c 作为预积分量测的协方差阵 xff1b 计算预
  • java核心内容——int和Integer有什么区别?

    java核心内容 int和Integer有什么区别 xff1f 1 典型回答2 知识扩展1 理解自动装箱 拆箱2 源码分析3 原始类型线程安全4 Java 原始数据类型和引用类型局限性 1 典型回答 int 是我们常说的整形数字 xff0c
  • docker虚拟机(可显示界面)

    1 docker是什么 xff1f 官方解释是容器 xff0c 是一种轻量化的虚拟机 与virtual box等虚拟机应用相比 xff0c 个人的使用体验是 xff0c 更加的方便快捷 xff0c 适合一个应用起一个虚拟机 2 docker
  • 编译DBoW2出现:fatal error: opencv/cv.h: 没有那个文件或目录 错误

    解决方法 xff1a 将各文件中的 include lt opencv cv h gt 替换为 include lt opencv2 opencv hpp gt 即可 另外 xff0c ORB SLAM要求OpenCV 3 0 xff0c
  • 揭晓3类AI无法取代的工作,高学历竟没有优势!

    整理 朱珂欣 出品 CSDN程序人生 xff08 ID xff1a coder life xff09 上周 xff0c IBM 就打响 AI 取代潮 的第一枪 xff0c CEO Arvind Krishna 在接受彭博社采访时表示 xff
  • 嵌入式Linux书籍清单

    原文链接 xff1a 重磅推荐 嵌入式Linux书籍清单 Linux入门C语言数据结构ARM裸机Linux驱动Linux应用Shell脚本Makefile Linux入门 作为嵌入式开发人员 xff0c 我们没有必要把精力放到使用哪个Lin
  • STM32串口之环形队列接收数据

    原文链接 xff1a STM32串口之环形队列接收数据 码代码的应该学数据结构都学过队列 环形队列是队列的一种特殊形式 xff0c 应用挺广泛的 因为有太多文章关于这方面的内容 xff0c 理论知识可以看别人的 xff0c 下面写得挺好的
  • Ubuntu18下xsens IMU的驱动安装及使用imu_utils标定

    最近在做xsens IMU的标定工作 xff0c 网上资源很多很杂 xff0c 打算按自己的操作过程 细节及遇到的问题记录一下 xff0c 里面有参考的博文都附了链接 主体可参考此博文 xff1a VIO 中 IMU 的标定流程 1 3 i
  • 常见 Promise 面试问题

    前端面试过程中 xff0c 基本都会问到 Promise xff0c 如果你足够幸运 xff0c 面试官问的比较浅 xff0c 仅仅问 Promise 的使用方式 xff0c 那么恭喜你 事实上 xff0c 大多数人并没有那么幸运 所以 x