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

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

作者头像
用户1687375
发布于 2019-07-30 08:47:20
发布于 2019-07-30 08:47:20
98200
代码可运行
举报
文章被收录于专栏:较真的前端较真的前端
运行总次数: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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
[享学Feign] 十、Feign通过feign-jackson模块天然支持POJO的编码和解码
上文介绍了Feign的Client相关模块,体验到Feign核心内容的高扩展性同时,亦能明显感觉到其子模块其实为对Feign核心功能的延伸,让其更能适应复杂的生产环境要求。
YourBatman
2020/02/21
6K0
[享学Feign] 五、原生Feign的编码器Encoder、QueryMapEncoder
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
8.9K0
[享学Feign] 五、原生Feign的编码器Encoder、QueryMapEncoder
[享学Feign] 六、原生Feign的解码器Decoder、ErrorDecoder
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
19.4K0
[享学Feign] 六、原生Feign的解码器Decoder、ErrorDecoder
[享学Feign] 九、Feign + OkHttp和Feign + Apache HttpClient哪个更香?
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
6.4K0
[享学Feign] 九、Feign + OkHttp和Feign + Apache HttpClient哪个更香?
[享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler...
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
3.9K0
[享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler...
[享学Feign] 一、原生Feign初体验,Netflix Feign or Open Feign?
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
5.6K0
[享学Feign] 一、原生Feign初体验,Netflix Feign or Open Feign?
Feign实现文件上传下载
Feign框架对于文件上传消息体格式并没有做原生支持,需要集成模块feign-form来实现。
编程随笔
2022/04/29
1.3K0
[享学Feign] 三、原生Feign的核心API详解(一):UriTemplate、HardCodedTarget...
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
4.3K0
[享学Feign] 三、原生Feign的核心API详解(一):UriTemplate、HardCodedTarget...
Feign-声明式java Http客户端
Feign 是Netfilx开源的一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign
kl博主
2018/04/13
4K0
[享学Feign] 十一、Feign通过feign-slf4j模块整合logback记录日志
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
5.2K0
[享学Feign] 十一、Feign通过feign-slf4j模块整合logback记录日志
快捷实现http客户端神器-feign(私人定制扩展篇)
Feign允许我们通过注解的方式实现http客户端的功能,Feign能用最小的性能开销,让我们调用web服务器上基于文本的接口。同时允许我们自定义编码器、解码器和错误处理器等等
lyb-geek
2019/07/22
2.8K0
快捷实现http客户端神器-feign(私人定制扩展篇)
Feign实现动态URL
动态URL的需求场景: 有一个异步服务S,它为其他业务(业务A,业务B...)提供异步服务接口,在这些异步接口中执行完指定逻辑之后需要回调相应业务方的接口。
编程随笔
2022/04/29
2.8K0
Feign实现动态URL
Feign上传文件
今天给大家介绍下在Feign中如何调用文件上传接口,进行文件上传操作。 这边文章讲的Feign不是Spring Cloud Feign,是原始Feign的使用。 在一些比较老的,不是Spring Cloud的项目中,我们也可以用Feign来进行接口的调用。 关于Feign的使用可以参考我的这篇文章:如何优雅的使用Feign调用接口 使用Feign来上传文件,首先你得有一个上传文件的接口,我们假设上传地址如下: POST http://localhost:8080/file/upload 参数的话就一个fil
猿天地
2018/04/03
1.6K0
我用 Dubbo 传输文件,差点被开除。。。
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/07/06
3930
我用 Dubbo 传输文件,差点被开除。。。
非Spring环境下的Ribbon+Feign使用宝典
Ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为,一般都是Ribbon搭配Feign一起使用;Feign默认集成了ribbon
白石
2019/08/23
1.3K0
[享学Feign] 八、Feign是如何生成接口代理对象的?Feign实例的构建器Feign.Builder详解
代码下载地址:https://github.com/f641385712/feign-learning
YourBatman
2020/02/21
7.2K0
每天20分钟之feign
feign对各类http调用包进行了抽象,我们不必自己去调用http包,feign进行了封装
李子健
2022/07/24
2320
同事使用 Dubbo 传输文件,被点名批评!
公司之前有一个 Dubbo 服务,其内部封装了腾讯云的对象存储服务 SDK,目的是统一管理这种三方服务的SDK,其他系统直接调用这个对象存储的 Dubbo 服务。这样可以避免因平台 SDK 出现不兼容的大版本更新,从而导致公司所有系统修改跟着升级的问题。
业余草
2021/12/06
3930
同事使用 Dubbo 传输文件,被点名批评!
SpringCloud原理之feign
前面一节我们学习了一下eureka,我们来回顾一下,首先它是一个cs架构,分为客户端和服务端,
用户9927510
2022/07/29
6550
SpringCloud原理之feign
Spring Cloud-Feign设计原理
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/details/82821294
亦山
2019/05/25
2.7K0
推荐阅读
相关推荐
[享学Feign] 十、Feign通过feign-jackson模块天然支持POJO的编码和解码
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验