Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >手写源码系列(二)——Promise相关方法

手写源码系列(二)——Promise相关方法

作者头像
用户1687375
发布于 2019-07-30 08:47:20
发布于 2019-07-30 08:47:20
98410
代码可运行
举报
文章被收录于专栏:较真的前端较真的前端
运行总次数:0
代码可运行

本文首发于知乎专栏——前端面试题汇总,大家可以通过文章底部的阅读原来来访问原文地址

手写Promise相关方法

Promise是面试中经常遇到的,如果面试中面试官问你Promise.all()怎么用,那你面试的岗位可能是差不多高级前端开发的岗位,但如果让你手写一个Promise.all()那你面试的岗位应该就是资深/专家前端开发的岗位了

上期回顾

上期我们实现了函数的call()bind()apply()方法。

Promise.all()

先回顾一下Promise.all()的用法

Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

例子如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]
手写实现Promise.all()方法

直接上代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.myAll = function (iterators) {
  const promises = Array.from(iterators)
  const len = promises.length
  let count = 0
  let resultList = []
  return new Promise((resolve, reject) => {
    promises.forEach((p, index) => {
      Promise.resolve(p)
        .then((result) => {
          count++
          resultList[index] = result
          if (count === len) {
            resolve(resultList)
          }
        })
        .catch(e => {
          reject(e)
        })
    })
  })
}

核心思路:

  1. Promise.myAll()返回的肯定是一个promise对象,所以可以直接写一个return new Promise((resolve, reject) => {})(这应该是一个惯性思维)
  2. 遍历传入的参数,用Promise.resolve()将参数"包一层",使其变成一个promise对象
  3. 关键点是何时"决议",也就是何时resolve出来,在这里做了计数器(count),每个内部promise对象决议后就将计数器加一,并判断加一后的大小是否与传入对象的数量相等,如果相等则调用resolve(),如果任何一个promise对象失败,则调用reject()方法。

一些细节:

  1. 官方规定Promise.all()接受的参数是一个可遍历的参数,所以未必一定是一个数组,所以用Array.from()转化一下
  2. 使用for…of进行遍历,因为凡是可遍历的变量应该都是部署了iterator方法,所以用for…of遍历最安全

Promise.race()

回顾一下race的用法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'one');
});

var promise2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then(function(value) {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// expected output: "two"

有了Promise.all()的铺垫,race就好写多了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.myRace = function (iterators) {
    return new Promise((resolve, reject) => {
        for (let p of iterators) {
            Promise.resolve(p)
                .then((result) => {
                    resolve(result)
                })
                .catch(e => {
                    reject(e)
                })
        }
    })
}

核心思路:

  1. 谁先决议那么就返回谁,所以将all的计数器和逻辑判断全部去除掉就可以了。

Promise.prototype.finally()

回顾一下正常用法。

finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。

这避免了同样的语句需要在then()catch()中各写一次的情况。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let isLoading = true;

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); })
  .finally(function() { isLoading = false; });
手写实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.prototype.myFinally = function finallyPolyfill(callback) {
    return this.then(function(value) {
            return Promise.resolve(callback()).then(function() {
                return value;
            });
        }, function(reason) {
            return Promise.resolve(callback()).then(function() {
                Promise.reject(reason);
            });
        });
};

核心思路:

  1. 当前this指向的是当前Promise对象,所以可以直接用this.then()
  2. then回调中的两个参数,一个是成功时的回调,另一个是失败是的回调,利用这个两个参数处理当前promise对象的两种不同情况
  3. 无论如何都要调用传入的callback函数,并且将当前promise的决议值继续传递下去

一些细节:

callback传入的有可能仍然是一个Promsie对象,如果真的是Promise对象,要等该promise决议之后才能执行之后then()方法,但是这个then()中拿到的是finally()之前的决议值,有种"决议值穿透"的感觉。

PS:我在网上找到了最权威的写法,毫无破绽 https://github.com/matthew-andrews/Promise.prototype.finally/blob/master/finally.js

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 较真的前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
老哥,可以加你的微信问点问题吗
老哥,可以加你的微信问点问题吗
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
因为实现不了Promise.all,一场面试凉凉了
(ಥ﹏ಥ)曾经真实发生在一个朋友身上的真实事件,面试官让他手写一个Promise.all,朋友现场发挥不太好,没有写出来,事后他追问面试官给的模糊评价是基础不够扎实,原理性知识掌握较少... 当然整场面试失利,并不仅仅是这一个题目,肯定还有其他方面的原因。
前端胖头鱼
2022/07/25
5150
因为实现不了Promise.all,一场面试凉凉了
分享4 个你可能感兴趣的 TikTok 前端面试题
英文 | https://javascript.plainenglish.io/tiktok-interview-4-front-end-questions-youll-be-interested-to-know-about-0c00d4154786
winty
2024/01/14
5220
分享4 个你可能感兴趣的 TikTok 前端面试题
手写Promise的相关方法
Promise 作为 JS 社区的异步解决方案,为开发者提供了.then()、Promise.resolve()、Promise.reject()等基本方法。除此之外,为了更方便地组合和控制多个的 Promise 实例,也提供了.all()、.race()等方法。
心谭博客
2020/04/21
1K0
按照 Promise/A+ 手写Promise,通过promises-aplus-tests的全部872个测试用例
链接:https://juejin.cn/post/6910500073314975758
落落落洛克
2021/01/07
9910
如何写出一个惊艳面试官的 Promise【近 1W字】 前言源码1.Promise2.Generator3.async 和 await4.Pro
1.高级 WEB 面试会让你手写一个Promise,Generator 的 PolyFill(一段代码); 2.在写之前我们简单回顾下他们的作用; 3.手写模块见PolyFill.
火狼1
2020/05/09
7320
如何写出一个惊艳面试官的 Promise【近 1W字】
                            前言源码1.Promise2.Generator3.async 和 await4.Pro
前端高频手写面试题
Object.is不会转换被比较的两个值的类型,这点和===更为相似,他们之间也存在一些区别
helloworld1024
2022/12/15
1.2K0
初识Promise
Promise是异步编程的一种优雅的解决方案。它相比于回调和事件交互,更加合理和强大。它改善了深度回调的问题。 回调里面还有回调,层级较深的,代码看起来特别凌乱。而通过事件交互会多做一些工作,比如发送事件,监听事件,事件回调等操作。而Promise能够获取异步操作的结果,这样的话,方便进一步处理接下来的逻辑。
Umbrella1024
2021/03/23
5510
前端异步技术之Promise
由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4
Jack Chen
2019/03/06
5260
JS中Promise理解与应用
Promise是ES6一个新的特性,本身是个对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。创建一个Promise对象:
Light413
2020/04/08
1.2K0
JS中Promise理解与应用
带你手写Promise身上的几个方法,拷打面试官
Promise的手写是面试中一个常考的考点。希望我的文章能够帮到大家,在被问到Promise时能够露出一个自信的微笑。
用户6256742
2024/06/30
1340
手写一个Promise/A+,完美通过官方872个测试用例
前段时间我用两篇文章深入讲解了异步的概念和Event Loop的底层原理,然后还讲了一种自己实现异步的发布订阅模式:
蒋鹏飞
2020/10/15
7690
手写一个Promise/A+,完美通过官方872个测试用例
JS 原生方法原理探究(十):如何手写实现 Promise/A+ 及相关方法?
Promise 构造函数的作用是创建一个 promise 实例。对于一个 promise 实例来说,它会有几个基本的属性:status 记录 promise 的状态(初始为 pending),value 记录 promise resolve 的值(初始为 null),reason 记录 promise reject 的值(初始为 null)。
Chor
2021/09/08
8220
前端二面手写面试题总结
then 方法返回一个新的 promise 实例,为了在 promise 状态发生变化时(resolve / reject 被调用时)再执行 then 里的函数,我们使用一个 callbacks 数组先把传给then的函数暂存起来,等状态改变时再调用。
helloworld1024
2022/10/27
8510
Promise的几个方法
我们都会觉得虽然是链式调用,对比回调会清晰一点,但是并没有想象中的那么美好。所以Promise提供了几个方法。
wade
2020/04/24
3520
Promise
Promise对象用于呈现异步操作事件的完成/失败结果。 此篇文章翻译自Promise,原文章太长,因此自己在这里做了简化,以便自己加强认识和理解。 实际上Promise的用法非常简单,自己不太理解的只是then() finally() catch()在链式调用时缺省回调函数的情况
云台大树
2021/07/30
7310
好好学习JS异步原理
平常在工作中,我们经常与异步打交道,无论是函数节流、防抖,异步请求,都是异步操作。那么我们会经常使用setTimeout,Promise,Async/Await这三个东西。那么我们是真的了解这些api和语法糖他们的原理以及知识吗?本篇文章将从尽可能的说明白个中的原理和知识。
LamHo
2022/09/26
1.4K0
好好学习JS异步原理
对于Promise的简单理解 ?
当谈到Promise的时候,你肯定顺便听到回调、异步、这样的玩意。其实说得通俗一点,Promise就是一种写代码的方式,并且是用来写JavaScript编程中的异步代码的。
青梅煮码
2023/01/16
2840
对于Promise的简单理解 ?
图解JavaScript——代码实现【2】(重点是Promise、Async、发布/订阅原理实现)
本节主要阐述六种异步方案:回调函数、事件监听、发布/订阅、Promise、Generator和Async。其中重点是发布/订阅、Promise、Async的原理实现,通过对这几点的了解,希望我们前端切
前端迷
2020/10/26
7990
图解JavaScript——代码实现【2】(重点是Promise、Async、发布/订阅原理实现)
Promise all方法
Promise.all方法接收一个Promise对象数组,并返回一个新的Promise对象。当传入的所有Promise对象都成功完成时,新的Promise对象将被标记为已完成,并将一个包含所有结果的数组作为其结果值;如果其中任何一个Promise对象被标记为失败,则新的Promise对象将被标记为失败,并将失败的原因作为其结果。
堕落飞鸟
2023/05/23
3630
带你写出符合Promise/A+规范Promise的源码
Promise是前端面试中的高频问题,如果你能根据PromiseA+的规范,写出符合规范的源码,那么我想,对于面试中的Promise相关的问题,都能够给出比较完美的答案。
刘小夕
2020/07/29
9000
带你写出符合Promise/A+规范Promise的源码
相关推荐
因为实现不了Promise.all,一场面试凉凉了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验