手撕代码彻底理解Promise
创始人
2024-01-20 13:04:39

一、异步

  1. js是单线程的,只能同步进行,优化用户体验,解决该问题产生了异步的操作
  2. 早先异步的解决方案,回调函数(callback)

二、回调函数的问题

  1. 错误处理困难
  2. 有依赖的执行回调造成回调地狱
  3. 无依赖的并行回调执行代码很冗余

解释一 :错误处理困难

getJson('api/a.json',function(){})// 若上面的函数发生错误 我们无法使用try catch 捕获错误
// 不能这样使用
try{getJson('api/a.json',function(){})
}catch(err=>{console.log(err)
})
// 原因 是回调函数和开始任务中这段代码不在同一个事件循环步骤

解释二:有依赖的执行回调造成回调地狱

这个很常见,比如一个场景,我们需要先拿到用户信息调用a接口,在用户信息的基础上我们需要获取用户的课程调用b接口,拿到用户的课程后我们需要判断该课程是否过期调用c接口

回调地狱产生

解释三:无依赖的并行回调执行代码很冗余

比如 我们需要从三个接口分别获取三份数据,然后在某个方法中同时使用这个三个数据,

由于我们不知道,数据返回的先后,只能分别在获取三分数据的接口中去调用封装好的函数去同时使用这三份数据。

三、promise登场

promise解释

可以简单的理解为对于异步任务结果的一个占位符。我现在还没拿到数据,但是我将来会得到。

promise生命周期

  1. pending(等待阶段 未完成状态
  2. fulfilled (resolve函数调用 已完成状态
  3. rejected (reject函数被调用 已完成状态

promise的执行顺序


promise执行顺序

结果
start code
pro.html:12 进入a promise
pro.html:29 进入b promise
pro.html:41 end code
pro.html:35 b promise 成功
pro.html:15 进入a promise 定时器
pro.html:22 a promise 成功

显示拒绝和隐式拒绝

显示拒绝是我们手动调用reject函数

隐式拒绝是业务代码发生异常错误

四、promise链式调用 解决回调地狱

相对callback会好一些 但是还不是最完美方案(后面的aysnc/await 是同步书写的执行异步方法的完美方案)

getJson('api/a.json')
.then(user=>getJson(user[0].courseUrl))
.then(course=>getJson(canuseUrl))
.catch(e=>{console.log(e)
}))

五、Promise.all

当所有的子Promise都完成,该Promise完成,返回值是全部值的数组。

如果有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果。

Promise.all([getJson('api/a,json'),
getJson('api/b,json'),
getJson('api/c,json')]).then(res=>{const a = res[0];const b = res[1];const c = res[2];
}).catch(e=>{console.log(e)
})

六、Promise.race

它有任意一个返回成功后,就算完成,但是 进程不会立即停止

Promise.race([getJson('api/a,json'),
getJson('api/b,json'),
getJson('api/c,json')]).then(res=>{if(res !== null){//执行操作}
}).catch(e=>{console.log(e)
})

场景:利用Promise.race 做请求超时处理

把异步操作和定时器放到一起,如果定时器先触发,认为超时,告知用户

let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('成功了')}, 2000);
})
let p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')    }, 5000);
})
Promise.race([p1, p2]).then((result) => {console.log(result)               //['成功了', 'success']
}).catch((error) => {console.log(error)
})

七、promise封装异步请求


promise 封装异步请求

八、 Promise实现原理

/*** promsie 主要有7个属性* state 状态* value 成功返回值* reson 错误信息* resolve 方法 执行成功调用* reject 方法 执行失败调用* then 方法* **/// 简单版本function myPromise(constructor) {let self = this;self.status = 'pending';self.value = undefined;self.reason = undefined;function resolve(value) {if (self.status === 'pending') {self.value = value;self.status = 'fulfilled';}}function reject(reason) {if (self.status === 'pending') {self.value = reason;self.status = 'rejected';}}// 捕获构造异常try {constructor(resolve, reject);} catch (e) {reject(e);}}myPromise.prototype.then = function (onFulfilled, onRejected) {let self = this;switch (self.status) {case 'fulfilled':onFulfilled(self.value);break;case 'rejected':onRejected(self.reason);break;default:}};// 测试let p = new myPromise((resolve, reject) => {resolve(1);});p.then((res) => {console.log(res);});

参考:

  1. 《javascript 忍着密术 第二版》P145-157
  2. Promise实现原理

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
金属硬度排行 各种金属硬度 世界上最硬的东西排名分别为硫化碳块,石墨烯,金刚石,金属玻璃和金属锇。这五种物体几乎是整个世界上最坚...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...