Promise 想必大家都十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。

以下 promise 均指代 Promise 实例,环境是 Node.js。

题目一

const promise = new Promise((resolve, reject) => {console.log(1)resolve()console.log(2)
})
promise.then(() => {console.log(3)
})
console.log(4)复制代码

运行结果:

1
2
4
3复制代码

解释:Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。

题目二

const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')}, 1000)
})
const promise2 = promise1.then(() => {throw new Error('error!!!')
})console.log('promise1', promise1)
console.log('promise2', promise2)setTimeout(() => {console.log('promise1', promise1)console.log('promise2', promise2)
}, 2000)复制代码

运行结果:

promise1 Promise { <pending> }
promise2 Promise { <pending> }
(node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!
(node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
promise1 Promise { 'success' }
promise2 Promise {<rejected> Error: error!!!at promise.then (...)at <anonymous> }复制代码

解释:promise 有 3 种状态:pending、fulfilled 或 rejected。状态改变只能是 pending->fulfilled 或者 pending->rejected,状态一旦改变则不能再变。上面 promise2 并不是 promise1,而是返回的一个新的 Promise 实例。

题目三

const promise = new Promise((resolve, reject) => {resolve('success1')reject('error')resolve('success2')
})promise.then((res) => {console.log('then: ', res)}).catch((err) => {console.log('catch: ', err)})复制代码

运行结果:

then: success1复制代码

解释:构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用,呼应代码二结论:promise 状态一旦改变则不能再变。

题目四

Promise.resolve(1).then((res) => {console.log(res)return 2}).catch((err) => {return 3}).then((res) => {console.log(res)})复制代码

运行结果:

1
2复制代码

解释:promise 可以链式调用。提起链式调用我们通常会想到通过 return this 实现,不过 Promise 并不是这样实现的。promise 每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用。

题目五

const promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('once')resolve('success')}, 1000)
})const start = Date.now()
promise.then((res) => {console.log(res, Date.now() - start)
})
promise.then((res) => {console.log(res, Date.now() - start)
})复制代码

运行结果:

once
success 1005
success 1007复制代码

解释:promise 的 .then 或者 .catch 可以被调用多次,但这里 Promise 构造函数只执行一次。或者说 promise 内部状态一经改变,并且有了一个值,那么后续每次调用 .then 或者 .catch 都会直接拿到该值。

题目六

Promise.resolve().then(() => {return new Error('error!!!')}).then((res) => {console.log('then: ', res)}).catch((err) => {console.log('catch: ', err)})复制代码

运行结果:

then: Error: error!!!at Promise.resolve.then (...)at ...复制代码

解释:.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获,需要改成其中一种:

return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')复制代码

因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))

题目七

const promise = Promise.resolve().then(() => {return promise})
promise.catch(console.error)复制代码

运行结果:

TypeError: Chaining cycle detected for promise #<Promise>at <anonymous>at process._tickCallback (internal/process/next_tick.js:188:7)at Function.Module.runMain (module.js:667:11)at startup (bootstrap_node.js:187:16)at bootstrap_node.js:607:3复制代码

解释:.then.catch 返回的值不能是 promise 本身,否则会造成死循环。类似于:

process.nextTick(function tick () {console.log('tick')process.nextTick(tick)
})复制代码

题目八

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)复制代码

运行结果:

1复制代码

解释:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。

题目九

Promise.resolve().then(function success (res) {throw new Error('error')}, function fail1 (e) {console.error('fail1: ', e)}).catch(function fail2 (e) {console.error('fail2: ', e)})复制代码

运行结果:

fail2: Error: errorat success (...)at ...复制代码

解释:.then 可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。.catch.then 第二个参数的简便写法,但是它们用法上有一点需要注意:.then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch 可以捕获之前的错误。当然以下代码也可以:

Promise.resolve().then(function success1 (res) {throw new Error('error')}, function fail1 (e) {console.error('fail1: ', e)}).then(function success2 (res) {}, function fail2 (e) {console.error('fail2: ', e)})复制代码

题目十

process.nextTick(() => {console.log('nextTick')
})
Promise.resolve().then(() => {console.log('then')})
setImmediate(() => {console.log('setImmediate')
})
console.log('end')复制代码

运行结果:

end
nextTick
then
setImmediate复制代码

解释:process.nextTickpromise.then 都属于 microtask,而 setImmediate 属于 macrotask,在事件循环的 check 阶段执行。事件循环的每个阶段(macrotask)之间都会执行 microtask,事件循环的开始会先执行一次 microtask。


本文作者为石墨文档的 nswbmw 同学。

Promise 必知必会(十道题)相关推荐

  1. MySQL必知必会——第十五章联结表

    联结表 本章将介绍什么是联结,为什么要使用联结,如何编写使用联结的SELECT语句. 联结 SQL最强大的功能之一就是能在数据检索查询的执行中联结(join)表. 在能够有效地使用联结前,必须了解关系 ...

  2. mysql函桌为之一的_MYSQL必知必会读书笔记第十和十一章之使用函数处

    mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 拼接字段 存储在数据库表中的 ...

  3. 《MySQL必知必会》学习笔记十(增删改语句使用)------掌握部分

    MySQL必知必会知识预览 第一章--了解SQL 第二章--MySQL简介 第三章--使用MySQL 第四章--检索数据 第五章--排序检索数据 第六章--过滤数据 第七章--数据过滤 第八章--用通 ...

  4. mysql必学十大必会_MYSQL 学习(一)--启蒙篇《MYSQL必知必会》

    MYSQL必知必会 一. DDL 数据定义语言 Data Definition Language 是指CREATE,ALTER和DROP语句. DDL允许添加/修改/删除包含数据的逻辑结构,或允许用户 ...

  5. c2064 项不会计算为接受0个参数的函数_【JS必知必会】高阶函数详解与实战

    本文涵盖 前言 高级函数概念 函数作为参数的高阶函数 map filter reduce sort详解与实战 函数作为返回值的高阶函数 isType函数与add求和函数 如何自己创建高阶函数 前言 一 ...

  6. 程序员必知必会之maillist篇

    程序员必知必会之maillist篇        本文最初由恋花蝶发表于http://blog.csdn.net/lanphaday,可以随意转载,但未经同意不得增删修改,转载应保留本声明,否则追究责 ...

  7. 程序员必知必会之blog篇

    程序员必知必会之blog篇 网易广州       赖勇浩(http://blog.csdn.net/lanphaday) 本文最初发表于恋花蝶的博客(http://blog.csdn.net/lanp ...

  8. 前端必知必会HTTP请求系列(二)简单一点的HTTP协议

    http协议用户客户端和服务器之间的通信 http协议和TCP/IP协议族内的其他众多协议相同,用于客户端和服务器之间的通信. 那么问题来个如果两台服务器之间一台服务器向另一台服务器进行接口请求那谁是 ...

  9. gns3中两个路由器分别连接主机然后分析ip数据转发报文arp协议_关于TCP/IP,必知必会的十个问题!...

    本文整理了一些TCP/IP协议簇中需要必知必会的十大问题,既是面试高频问题,又是程序员必备基础素养. TCP/IP十个问题 TCP/IP十个问题 一.TCP/IP模型 TCP/IP协议模型(Trans ...

  10. 【总结记录】《MySQL必知必会》读后笔记,结合 leetcode 例题理解

    文章目录 一. <MySQL知会>读后笔记 1. 零散的前文知识 2. 连接数据库 3. 检索数据(重点开始了) 4. 排序.过滤数据 5. 通配符.正则表达式 6. 汇总数据 7. 分组 ...

最新文章

  1. Linux下的vim文本替换,Linux下文本的vim文本替换
  2. Codeforces Gym 100418K Cards 暴力打表
  3. android的NDK和java进行本地socket通信
  4. python图形化界面按钮_Python-PyQt5-图形可视化界面(3)--按钮--Qpushbutton
  5. 美国城市_泡泡图如何揭示美国最适合居住的城市
  6. php mysql_fetch_array($result)_PHP mysqli_free_result()与mysqli_fetch_array()函数
  7. python怎么定义一个变量为空列表_python – 为什么一个类变量没有在列表理解中定义,但另一个是?...
  8. 回文数五位和六位c语言,特殊回文数
  9. 会员卡券领取 小程序_新增卡券功能在哪 微信小程序内直接领取卡券方法
  10. java-Map接口
  11. 有梦想,就去追,不犹豫,不后悔
  12. pycharm 中 pydev debugger: CRITICAL WARNING: This version of python seems to be incorrectly compiled
  13. root后没反应怎么办,没有root怎么办?
  14. 开发内功修炼网络篇电子书出炉!!!
  15. 【附源码】计算机毕业设计SSM汽车维修服务系统
  16. MySQL数据库视频教程之扛得住的MySQL数据库架构
  17. 万字长文,会员体系拆解
  18. python写打开的excel 冲突_在Python中打开excel文件时出错
  19. PCL 点云DBSCAN聚类算法
  20. HoloLens开发笔记-制作传送门

热门文章

  1. java正则表达式验证_Java中的正则表达式电话号码验证
  2. tomcat7-maven-plugin-用于部署WAR的Tomcat Maven插件
  3. The Reactive Manifesto(响应式宣言)
  4. Qt程序移植到其他电脑上无法运行的解决方法
  5. box-sizing,你的宽高度计算对了吗?
  6. 日程表、学生课表插件
  7. MATLAB R2018a 安装教程
  8. javascript进阶课程--第三章--匿名函数和闭包
  9. 为linux系统引导和登录提供安全加固
  10. 刚装完系统的简单优化