十行代码实现高仿Promise
本文为饥人谷讲师若愚原创文章,首发于 前端学习指南。
问题
假设我们有一个需求:1. 获取用户所在的城市;2. 根据城市获取天气;3. 根据天气获取出行建议。那我们的代码应该是这样的
getCity(url1, function(){getWeather(url2, function(weather){getSuggestion(url3, function(suggestion){console.log(suggestion)})})
})
这就是典型的异步 callback 『回调地狱』,代码层层嵌套可读性很差。关于异步的解决方式可参考这篇文章 Node.js异步漫谈
使用 Promise 是解决上述问题的一种方式,这里我们不去讲如何去使用内置的 Promise,而是带大家手把手写一个 Promise。
思路
我们希望有一个工具,能让我们使用下面的的写法来实现上述功能
promise.then(getCity).then(getWeather).then(getSuggestion)
整理下思路:
- Tool 是一个对象
- Tool 有 then 这个方法
- 执行 then 方法返回的应该还是 Tool 对象
function Promise(){}
Promise.prototype.then = function(fn){//todo...return this
}
var promise = new Promise()
那如何实现异步操作序列执行呢?关键思路如下:
在 promise 对象内容维护一个数组,当执行 promise.then(getCity) .then(getWeather) .then(getSuggestion) 时把这几个函数依次放入数组中。注意此时这些函数并没有执行。
执行promise.resolve()时,会从数组中拿出一个函数去执行。函数执行的过程中在异步操作的结果到来后会再次自动调用 promise.resolve(),触发下一个函数的取出并执行,下一个函数结果到来后再次自动调用promise.resolve() ......,这样就实现了异步链式执行。和原子弹爆炸原理类似。
所以需要对原来的异步函数做一点小小的改动,在数据到来的地方,加一个promise.resolve,用于启动后续函数的执行
function getCity(){var xhr = new XMLHttpRequest()xhr.open(url, 'get', true)xhr.onload = function(){if (this.status == 200) {promise.resolve(xhr.responseText) //注意这里的promise.resolve}}xhr.send()
}
现在我们就能实现一个简易的 Promise 了,这里我们先暂不考虑特殊情况:
function Promise(){this.callbacks = []
}
Promise.prototype.then = function(fn){this.callbacks.push(fn) //调用 then 时把函数放入数组return this //返回当前对象供链式调用
}
Promise.prototype.resolve = function(data){var fn = this.callbacks.shift() //当调用resolve时拿出一个函数fn&&fn(data) //执行这个函数,并且把resolve的参数做参数
}var promise = new Promise()promise.then(getCity).then(getWeather).then(getSuggestion)promise.resolve() //启动function getCity(){setTimeout(function(){promise.resolve('杭州')}, 1000)
}
function getWeather(city){setTimeout(function(){promise.resolve(city + ' 晴天')}, 1000)
}
function getSuggestion(weather){setTimeout(function(){console.log(weather + ' 天气不错,可携女友与狗出行')}, 1000)
}
当然,如果觉得promise.resolve 单独启动一次看起来不舒服,也可以这样执行
getCity().then(getWeather).then(getSuggestion)function getCity(){setTimeout(function(){promise.resolve('杭州')}, 1000)return promise //注意这里
}
实现
到此为止我们已经写了一个简单的 Promise,甚至能满足很大一部分使用需求。但有个问题,每次异步操作可能存在失败的情况,而上面的代码并没有异步函数的失败处理。下面考虑异步的失败处理,原理和上面类似,可以阅读代码动手做个测试
class Promise {constructor (){this.callbacks = []this.oncatch = null}reject(result){this.complete('reject', result)}resolve(result){this.complete('resolve', result)}complete(type, result){if(type==='reject' && this.oncatch){this.callbacks = []this.oncatch(result)}else if(this.callbacks[0]) { var handlerObj = this.callbacks.shift()if(handlerObj[type]){handlerObj[type](result)}}}then(onsuccess, onfail){this.callbacks.push({resolve: onsuccess,reject: onfail})return this}catch(onfail){this.oncatch = onfailreturn this}}var promise = new Promise()fn1().then(fn2, onfn1error).then(fn3, onfn2error).catch(onerror)function fn1(){setTimeout(function(){if(Math.random()>0.5){promise.resolve('杭州')}else{promise.reject('fn1 error')}})return promise}
总结
现在我们已经手写了一个 Promise, 当然和浏览器内置对象Promise原理有些差异, 但至少『达到』类似的目的了
加微信号: astak10或者长按识别下方二维码进入前端技术交流群 ,暗号:写代码啦
每日一题,每周资源推荐,精彩博客推荐,工作、笔试、面试经验交流解答,免费直播课,群友轻分享... ,数不尽的福利免费送
十行代码实现高仿Promise相关推荐
- java使用微信表情代码_iOS高仿微信表情输入功能代码分享
最近项目需求,要实现一个类似微信的的表情输入,于是把微信的表情扒拉出来,实现了一把.可以从这里下载源码.看起来表情输入没有多少东西,不外乎就是用NSTextAttachment来实现图文混排,结果在实 ...
- 短链接java代码_java高仿新浪微博短链接地址生成工具ShortUrlGenerator.java
仿新浪微博 短链接地址生成工具 ShortUrlGenerator.java String sLongUrl = "http://tech.sina.com.cn/i/2011-03-23/ ...
- html5支付宝主页面代码,JavaScript高仿支付宝倒计时页面及代码实现
实现目标 一,页面在图一时开始进行倒计时(可以点击取消订单按钮,支付页面消失). 二,倒计时完毕,出现删除订单. 三,单击删除订单,弹出弹框,询问是否要真正删除订单. 四,单击确定,即可删除订单. 如 ...
- 飞机大战代码(高仿),完美复原原游戏,好玩到停不下来
分数展示 void Game::printScore() {if(score == 120 && flag_rank == 0){rank -= 3;flag_rank = 1;}el ...
- 高仿QQ电脑管家8 界面
去年发了高仿QQ2012登录界面,最近又优化了下代码,先看效果图 换肤 的代码和高仿QQ2012登录界面一样,代码请看那边; 这次主要是优化了控件的组合,和贴图方式 整体的框架: 首先是一个窗口,这里 ...
- github,源码,高仿 直播
仿花田:相亲网站 意中人 已在GitHub上开源 从头开始写一款开源app上线,相互学习 SlideMenuControllerSwift swift实现双侧边栏菜单 StepView github ...
- Android 高仿App项目归纳整理,持续更新中…
Android 高仿App项目归纳整理,持续更新中- Android高仿App项目整理,包含高仿了一些大公司的app,有基于Java,Kotlin,Flutter等语言的.对于开发我们自已的项目时可以 ...
- 如何使用MFC编写自定义UI界面【附高仿QQ 2014登陆界面范例程序】
地址: http://blog.csdn.net/hujkay作者:Jekkay Hu(34538980@qq.com)关键词:MFC, 编写异行窗体,自定义UI控件,VC++,异形控件,高仿QQ登陆 ...
- vue 判断同一数组内的值是否一直_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目
项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...
最新文章
- seaborn使用FacetGrid函数可视化山脊图(Ridgeline Plot with Seaborn)
- .NET Core 使用 nlog 进行日志记录
- ORACLE:RETURNING 子句
- python类库31[文件和目录os+os.path+shutil]
- 再度吐槽,PHP在centos7的安装方式稍不注意可能就打击你的积极性
- C++:gloox库进行协议扩展(使用自定义标签)
- cahrt框架 ios_iOS - Charts(一) - BarChartView
- Oracle全备增量备份脚本,ORACLE-RMAN:备份脚本(全库,增量)
- Cocos2d-x特殊节点对象(瓦片地图、粒子系统、视差滚动)概述
- mariadb 集群mysql_负载均衡的mariadb集群搭建
- 小米r1d安装php,小米路由器 一键安装LLM教程
- AGV机器人RFID传感器CK-G06A与西门子1200PLC应用手册
- 阿里云弹性计算研发团队如何从0到1自建SRE体系
- linux网络Netfilter与iptables技术
- 在线ps,修改证件照背景色
- Flutter 开发——识别iOS设备
- 牛逼的架构 vs ‘牛逼’ 的人生
- 在百度地图中叠加CAD图及GIS数据展示踩坑记
- 模仿斗地主玩法实现扑克牌的分发
- chrome浏览器安装插件显示程序包无效
热门文章
- android布局参照示例_约束布局Android示例–第2部分
- java面试宝典pdf下载_Java面试问答PDF电子书免费下载(250+问题,60页)
- 如何在Windows上安装Maven
- 深入了解人工智能专业怎么样
- 大数据的普及催生医疗信息技术市场蓝海
- Cloudera Hadoop 4 实战课程(Hadoop 2.0、集群界面化管理、电商在线查询+日志离线分析)...
- 日志服务(原SLS)新功能发布(5)--使用Logstash接入数据
- 查询软件和硬件列表清单[将文章里代码另存为 list.vbs,双击运行就会出现一个html页面]...
- live555+ffmpeg如何提取关键帧(I帧,P帧,B帧)
- 2012-13学年上半学期路由与交换课程设计-作业-2