前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Promise 详解

Promise 详解

作者头像
前端知知
发布2022-09-29 19:14:23
4520
发布2022-09-29 19:14:23
举报
文章被收录于专栏:前端知知前端知知

本文旨在探讨Promise 出现背景、实现原理以及常用方法的实现。本文不是Promise的基本教程,如有不了解的读者,可以参考Promise mdn[1] 。

为什么需要Promise

在前端开发中,我们经常都会使用 setTimeout, XHR等方式进行异步调用,比如以下一个简单请求例子:

代码语言:javascript
复制
//ajax 是封装的XHR请求函数,此处省略具体实现
ajax({
 method: 'GET',
 url: '/url',
 data: {
  id: 'xxx'
 }
}, (response) => {
 // do something;
})

通常会在请求结束之后进行数据处理,比如修改dom 的展示等等;单个实现比较简单直接;但是在实际业务场景中,并不是单一的数据请求,往往会遇到下一个请求依赖前置的请求。比如我们先要获取商品的信息id, 然后去查询详情数据,我们通常处理会如下:

代码语言:javascript
复制
ajax({method: 'GET',
 url: '/get',
 data: {
  id: 'xxx'
 }
}, (response) => {
 // do something;
 ajax({}, () => {
  //...
 })
})

如果依赖层次过多的话会出现多层嵌套,对于代码的易读性和可维护性来说都是很大的挑战。Promise 的出现很大程度解决上述问题。我们可以具体来看看Promise实现原理。

实现原理

Promise 主要通过以下两步来解决回调嵌套问题:

实现回调函数的延时绑定。创建Promise对象p1 后,我们可以在任何地方使用p1.then 来执行具体的回调,实现回调函数的延时绑定:

代码语言:javascript
复制
p1 = new Promise((resovle, reject) => {
 // 指定具体的异步操作
 setTimeout(() => {
  resovle('promise')
 }, 1000)
});
// 通过then 方法绑定回调函数
p1.then((data) => { 
 console.log(data);
})

将回调函数onResovle的返回值穿透到外层。假定onResovle返回值为returnVal,分为以下两种情况:

  • 如果returnVal不为Promise对象,那么使用returnVal作为then 返回的新Promise的值。
  • 如果returnVal是Promise对象, 则会等该Promise对象(即returnVal)的状态发生变化才发生调用,并且新的Promise 对象状态和 returnVal状态相同。
代码语言:javascript
复制
let p1 = new Promise((resovle, reject) => {
 //执行业务逻辑
 resovle(100)
});
//p1 通过then 方法延迟绑定 onResovle 方法
const onResovle = (data) => {
 console.log(data);
 let p2 = new Promise((resovle, reject) => {
  resovle(data + 1);
 });
 return p2;
}
let p2 = p1.then(onResovle);
p2.then((data) => {
 console.log(data);
 console.log(p2);
})

具体实现可以参考Promise实现原理[2]

常用方法实现

Promise 本身拥有一些静态方法,比如 resovle, reject, race, all 等,其实现有很多,本文选择all 来展开具体实现:

  • 首先我们知道Promise.all 的输入参数为 Promises数组;
  • 其次返回对象为Promise 对象,并且返回对象Promise中的数据为执行promise 数组中的值;
  • 如果promises 数组中1个执行失败,则返回Promise状态和失败Promise执行状态一致。

那么了解到三个点后,可以容易的写出相关代码:

代码语言:javascript
复制
Promise.all2 = (promises) {
 return new Promise((resovle, reject) => {
  let result = [];
  let promiseResovleCnt = 0;
  for(let i = 0; i < promises.length; i++) {
   //需注意数组中的结果顺序和promises顺序一致
   promises[i].then((data) => {
                promiseResovleCnt++
                result[i] = data;
                if(promiseResovleCnt === promises.length) {
                 resovle(result);
                } 
   }, (reason) => {
    // 只要其中1个执行出错,那么Promise.all不在继续执行promises数组中其他对象
    reject(reason);
   })
  }
 })
}

总结

本文主要介绍了以下内容:

  • Promise 出现背景
  • Promise 如何解决嵌套问题
  • 常用的方法Promise.all 的实现

如文中有错误之处,欢迎留言斧正。

参考文献

[1] Promise mdn: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

[2] Promise实现原理:https://juejin.cn/post/6844903665686282253#heading-2

[3] 极客时间· 浏览器原理与实践: https://time.geekbang.org/column/intro/216

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要Promise
  • 实现原理
  • 常用方法实现
  • 总结
  • 参考文献
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档