关注「松宝写代码」,精选好文,每日一题
时间永远是自己的
每分每秒也都是为自己的将来铺垫和增值
作者:saucxs | songEagle
来源:原创
一、前言
2020.12.23日刚立的flag,每日一题,题目类型不限制,可以是:算法题,面试题,阐述题等等。
[图片上传失败...(image-6ade3b-1611230267349)]
往期「每日一题」:
第2道「[每日一题]ES6中为什么要使用Symbol?」(https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg)
第1道「一道面试题是如何引发深层次的灵魂拷问?」(https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA)
接下来是第3道:谈谈你对 promise 的理解?
二、谈谈你对 promise 的理解?
1、我们简单概括一下promise
Promise 是 ES6 新增的语法,解决了回调地狱的问题。
无论是ES6的Promise也好,jQuery的Promise也好,不同的库有不同的实现,但是大家遵循的都是同一套规范,所以,Promise并不指特定的某个实现,它是一种规范,是一套处理JavaScript异步的机制。
Promise 本质上就是一个绑定了回调的对象,而不是将回调传回函数内部。
所以,Promise在一定程度上解决了回调函数的书写结构问题,但回调函数依然在主流程上存在,只不过都放到了then(...)里面,和我们大脑顺序线性的思维逻辑还是有出入的。
2、我们说一下promise相关规范
可以把 Promise 看成一个状态机。初始是 pending 状态,可以通过函数 resolve 和 reject ,将状态转变为 resolved 或者 rejected 状态,状态一旦改变就不能再次变化。
then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending 状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then 调用就失去意义了。
then 方法可以被同一个 promise 调用多次。
值穿透
三、promise 是如何实现的?
1、Promise的简单使用
[图片上传失败...(image-e37daa-1611230267349)]
我们通过这种使用构建Promise实现的最初版本
2、Promise的大致框架
大致框架有了,但是Promise状态,resolve函数,reject函数,以及then等回调没有详细处理
[图片上传失败...(image-8df0ea-1611230267349)]
3、Promise的链式存储
我们先看一个例子:
[图片上传失败...(image-52d952-1611230267349)]
每间隔1秒打印一个数字,哈哈,这个不是真实的间隔1秒,汪汪,
这个的输出是啥?
打印顺序:1、2、3
这里我们能确认的是:
- 让a,b,c的只能在then的回调接收到
- 在连续的异步调用中,如何保证异步函数的执行顺序
Promise一个常见的需求就是连续执行两个或者多个异步操作,这种情况下,每一个后来的操作都在前面的操作执行成功之后,带着上一步操作所返回的结果开始执行。这里用setTimeout来处理.
[图片上传失败...(image-46ed1b-1611230267349)]
4、Promise的状态机制和执行顺序
为了保证Promise的异步操作时的顺序执行,这里给Promise加上状态机制
[图片上传失败...(image-991e19-1611230267349)]
5、Promise的递归执行
每个Promise后面链接一个对象,该对象包含onresolved,onrejected,子promise三个属性.
当父Promise 状态改变完毕,执行完相应的onresolved/onrejected的时候,拿到子promise,在等待这个子promise状态改变,在执行相应的onresolved/onrejected。依次循环直到当前promise没有子promise。
[图片上传失败...(image-3c50c5-1611230267349)]
6、Promise的异常处理
每个Promise后面链接一个对象,该对象包含onresolved,onrejected,子promise三个属性.
当父Promise 状态改变完毕,执行完相应的onresolved/onrejected的时候,拿到子promise,在等待这个子promise状态改变,在执行相应的onresolved/onrejected。依次循环直到当前promise没有子promise。
[图片上传失败...(image-5e4539-1611230267349)]
7、Promise的then的实现
then 方法是 Promise 的核心,这里做一下详细介绍。
promise.then(onFulfilled, onRejected)
一个 Promise 的then接受两个参数: onFulfilled和onRejected(都是可选参数,并且为函数,若不是函数将被忽略)
- onFulfilled 特性:
当 Promise 执行结束后其必须被调用,其第一个参数为 promise 的终值,也就是 resolve 传过来的值
在 Promise 执行结束前不可被调用
其调用次数不可超过一次
- onRejected 特性
当 Promise 被拒绝执行后其必须被调用,第一个参数为 Promise 的拒绝原因,也就是reject传过来的值
在 Promise 执行结束前不可被调用
其调用次数不可超过一次
- 调用时机
onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)
- 调用要求
onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值,在 严格模式(strict) 中,函数 this 的值为 undefined ;在非严格模式中其为全局对象。)
- 多次调用
then 方法可以被同一个 promise 调用多次
当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
- 返回
then方法会返回一个Promise,关于这一点,Promise/A+标准并没有要求返回的这个Promise是一个新的对象,但在Promise/A标准中,明确规定了then要返回一个新的对象,目前的Promise实现中then几乎都是返回一个新的Promise(详情)对象,所以在我们的实现中,也让then返回一个新的Promise对象。
promise2 = promise1.then(onFulfilled, onRejected);
- 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
- 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
- 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
- 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的拒因
不论 promise1 被 reject 还是被 resolve , promise2 都会被 resolve,只有出现异常时才会被 rejected。
每个Promise对象都可以在其上多次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,所以then不能返回this,因为then每次返回的Promise的结果都有可能不同。
[图片上传失败...(image-3685fe-1611230267349)]
8、Promise的值穿透
[图片上传失败...(image-45f0c4-1611230267349)]
我们来看一下这个题的输出:
[图片上传失败...(image-fbfb49-1611230267349)]
最终打结果是1而不是2.
我们再来看一下这个题的输出:
[图片上传失败...(image-8adada-1611230267349)]
谢谢支持
1、文章喜欢的话可以「分享,点赞,在看」三连哦。
2、作者昵称:saucxs,songEagle,松宝写代码。「松宝写代码」作者,每日一题,实验室等。一个爱好折腾,致力于全栈,正在努力成长的字节跳动工程师,星辰大海,未来可期。
3、长按下面图片,关注「松宝写代码」,是获取开发知识体系构建,精选文章,项目实战,实验室,每日一道面试题,进阶学习,思考职业发展,涉及到JavaScript,Node,Vue,React,浏览器,http等领域,希望可以帮助到你,我们一起成长~
[图片上传失败...(image-415b80-1611230267349)]
往期「每日一题」
1、JavaScript && ES6
第 28 题:【每日一题】(28题)面试官:原型链与构造函数结合方法继承与原型式继承的区别?
第 22 题:【每日一题】(22题)面试官问:var与const,let的主要区别是什么?
第 21 题:【每日一题】(21题)面试官问:谈谈JS中的 this 的绑定?
第 20 题:【每日一题】(20题)面试官问:谈谈JS中的 webSockets 的理解?
第 19 题:【每日一题】面试官问:谈谈JS中的 XMLHttpRequest 对象的理解?
第 18 题:【每日一题】面试官问:JS中的 Ajax 跨域与扩展 Comet ?
第 17 题:【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?
第 16 题:【每日一题】面试官问:JS中如何全面进行客户端检测?
第 15 题:【每日一题】面试官问:JS类型判断有哪几种方法?
第 14 题:【每日一题】面试官问:谈谈你对JS对象的创建和引申
第 13 题[每日一题]面试官问:['1', '2', '3'].map(parseInt)输出,原因,以及延伸?
第 12 题[每日一题]面试官问:JS引擎的执行过程(二)
第 11 题[每日一题]面试官问:JS引擎的执行过程(一)
第 10 题[每日一题]面试官问:详细说一下JS数据类型
第 8 题[每日一题]面试官问:谈谈你对ES6的proxy的理解?
第 7 题[每日一题]面试官问:for in和for of 的区别和原理?
第 6 题[每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?
第 3 道「「每日一题」面试官问你对 Promise 的理解?可能是需要你能手动实现各个特性」
第 2 道「[每日一题]ES6 中为什么要使用 Symbol?」
2、浏览器
- 第 9 题[每日一题]requestAnimationFrame不香吗?
3、Vue
- 第 5 道「每日一题」到底该如何回答:vue数据绑定的实现原理?
4、HTML5
- 第 29 道【每日一题】(29题)面试官:HTML-HTML5新增标签属性的理解?
5、算法
第 27 道【每日一题】(27题)算法题:如何使用多种解决方案来实现跳一跳游戏?
第 26 道【每日一题】(26题)算法题:最长公共前缀?
第 25 道【每日一题】(25题)算法题:堆数据结构-前 K 个高频元素?
第 24 道【每日一题】(24题)算法题:贪心算法-环游世界之如何加油?
第 4 道「每日一题」与面试官手撕代码:如何科学高效的寻找重复元素?
6、Node
- 第 23 道【每日一题】(23题)面试官问:详细描述事件循环Event Loop?
7、Http
- 第 1 道「一道面试题是如何引发深层次的灵魂拷问?」