前端通信:ajax设计方案(十)--- 完善Promise A+规范,增加mock数据功能
半年不迭代,迭代搞半年,说的就是我,这里有点尴尬了,直接进入主题吧
我记得在这篇博客的时候集成了Promise的,不过那个时候就简简单单的写了一点最基础,在一些特殊的case上,还是有点问题的,所以才有了这个博客。在拜读了w3c和PromiseA+规范之后,从头到尾详细的了解了Promise这个东西,然后自己亲手写了一个和es6文档拥有相同功能的库。
什么是promise?
promise是一个对象,表示单个异步操作的最终结果。
什么时候使用?
任何一门技术都不是一个“万金油”,只有在它最合适的场地出现,才是实现它最大价值的地方,so,Promise一样逃不过这个“真香”定律。
1. one-and-done操作模型
- 异步I / O操作:从存储API读取或写入的方法可以返回承诺。
- 异步网络操作:通过网络发送或接收数据的方法可以返回承诺。
- 长时间运行的计算:需要一段时间来计算某些东西的方法可以在另一个线程上完成工作,返回结果的承诺。
- 用户界面提示:要求用户回答的方法可以返回承诺。
2. One-Time "Events”模型
即使在已经履行或被拒绝之后也可以订阅,当某些事情只发生一次,并且作者经常想要在它已经发生之后观察它的状态
3.更多状态的变化
图像,字体等资源的加载loaded属性,这个属性仅在资源完全加载是才会实现,否则拒绝
不建议使用promise的场景
1. 任何一个可能不止一次发生的事件,都不是one-and-done模型的
2. 大的流数据,分步处理流数据,而无需将流的全部内容缓冲到内存中。
这里有个w3c组织搞出来的一个指南--Writing Promise-Using Specifications,建议大家拜读一下,虽然没有详细讲解规范,但是对于Promise使用场景和特性做了一次详细的介绍,包括我上面说的使用场景等等。
以上讲的更多偏向应用层的知识点,下面就让我们深入它的根本去了解Promise是如何实现的。
Promise本身是一种社区规范--Promises/A+,由Promise A+组织进行制定,它们提供了一个大纲和指导性的方案,只要能实现其所列规范,都可以视作实现了Promise A+,so,后面的各种变种啊,什么样的功能,都可以根据自己所需去设计,但是基础的方案按照A+ 组织规范实现就可以。
这个大纲比较啰嗦、枯燥、无味,so,我们靠3张我画的图去理解一下Promise
第一张:promise整体流程图
1. 实例化Promise的时候(定义内部状态的初始值等等),在同步状态下,首先会执行初始化代码,比如:new Promise((res,rej)=>{ console.log('这里就是初始化代码') }),然后再执行then方法。这个执行顺序在promise下是错误的,因为在实例代码中会首先改变Promise状态,但是前置的callback还没有在then方法中注入,所以要做推迟实例代码(setTimeout,可以将任务推到执行周期之后,宏任务),让then先跑起来,注入状态变更需要的前置依赖。
2. 在Promise规范中定义了,then方法,必须返回一个Promise,so,Promise2就是then的返回值。然后then的动作就是将所有需要前置依赖的回调函数,Promise状态,状态变化的value全都存储起来。
3. 等待推迟的实例代码(官方叫:异步)执行之后,触发了Promise状态的变化这个动作,然后去改变内部定义的状态,以及状态变化所要执行的操作。
4. 内部状态已经变化完成,但是return的Promise2状态还是pending,所以我们需要将自身的Promise和Promise2的状态进行同步以及是否可then的持续操作。
以上为Promise的整体流程思路,它就是这样跑起来的。不过知道这个流程以后,还是一知半解的,下面我们就对核心方法then进行详细剖析。
第二张:then方法核心解析
then方法需要分3个状态去解析
1. pending 状态
a. 首先实例化执行then方法,这个时候初始化的内部状态都是pending,这个时候,我们要做一个订阅和发布的设计,将then传入的resolve和reject的回调进行包装和存储,并订阅触发动作。(这边的包装是因为订阅的时候,不仅仅只是执行回调函数,还需要处理promise2的状态同步问题)
b. 在等待出发的状态的时候,这个时候状态没有变更,所以还是keep pending状态,而promise2也是pending;当promise触发了resolve,这个时候就需要处理之前订阅的回调了,先改变Promise自身的状态,然后调用callback,将callback的值传入解析函数,同步改变Promise2的状态;触发reject动作和resolve一样
c. 这样,在整个pending链路上,自身状态和promise2状态全都同步改变完成
2. resolve 状态
a. Promise内部状态以及变更完毕,内部会存储PromiseValue的值,直接获取PromiseValue的值作为参数,调起then方法传进来的resolveCallback的函数。
b. 使用同步解析函数,去同步改变Promise2的状态,以及后续可then的操作
3. reject 状态
该状态操作,同resolve操作,只是变更状态不一样
以上为then方法的所有操作流程,pending的时候最特殊,有个订阅发布设计来改变自身状态,然后同步改变Promise2的状态。其他resolve和reject,都是状态已经变更完毕,直接取状态变更的值,处理回调,然后同步改变Promise2的状态值。这边同步变更Promise2的规则,在A+的规范里是有定义的。
第三张:同步改变Promise2状态以及是否可继续then的操作
状态同步改变和是否可持续then的操作解析流程,都按照A+规范去判断
1. x代表callback的返回值,首先判断x和Promise2是否相等,相等抛出TypeError的错误(毕竟如果返回值x和Promise2是一个对象的话,那操作就没啥意义了)
2. 判断x是否是Promise对象,如果是的话,说明x是可支持then的,然后根据x的状态进行操作和同步改变Promise2的值,pending就等待执行结束,resolve和reject就分别改变Promise2的状态
3. 如果x不是Promise对象,判断x是否是对象或者function,否的话直接resolve Promise2状态。如果是的话,try-catch捕获,定义then = x.then是否报错,如果报错则reject掉Promise2状态。
4. 判断then是否是function,如果是则执行then操作,如果then方法执行了reject,则reject掉Promise2。
5. 如果then执行resolve,则将y替换掉x,重新和Promise2进行状态的同步改变。
PS:这里的x.then就是下面的这种状况,A+规范定义这样的返回值代表还是可then的,需要处理
temp.then(function (x) {
return {
then: function(resolve, reject) {
resolve(42);
}
}
})
至此整个Promise就结束了,从Promise怎么去运行,到核心代码then的处理,以及Promise2的同步改变,这就是所谓的Promise。回过头来发现,最值得佩服的是这种规范的设计思维,通过一种设计思维,将简单的技术化腐朽为神奇。所以,个人意见,程序员的进阶,最重要的不是代码的熟练度,而是思维的进阶。熟练度这个是每个人都可以靠时间堆积出来的,但是更高级的工程师,应该能从整体的视角去了解,然后规划和设计,将简单的技术化神奇,将复杂的问题化简单。
整个代码我就不贴出来了,太长了,可以到 github 上查看,功能完善了,支持all、race、resolve、reject方法
在ajax-js的库的变动,如下:
1. 替换之前有问题的createPromise的代码
2. 将get、post、postForm,obtainBlob,upload进行改造,改方法返回都是Promise(考虑这些都是one-and-done模型,而轮询和大文件切割上传2个方法是持续性操作,所以不做改变)
3. 删除postJSON、promiseAjax方法
ajax-js库增加新功能:mock功能
全局配置参数:
// mock功能
mock: {
isOpen: true,
mockData: {}
},
流程如下:
demo:
// 全局配置
ajax.config({
baseURL:'http://localhost:3000/',
mock: {
isOpen:true,
mockData: {
'post':'我是mock数据'
}
}
}) // 测试代码
function request_post() {
ajax.post('post',{data:'ajaxPost'})
.then(x=>{
console.warn(x)
})
}
测试结果:
注意:mockData的key是url的值,不是baseUrl+url的值
结束语:
ajax-js.1.9.2完成了,一直在思考还有什么需要改进的东西,之后的迭代需要走的方向
1. 完成http其他协议,put、delete等等
2. npm的包面向现代化,去除各种polyfill和一些兼容代码
3. 配置webpack自动打包压缩
4. 探索通信和其他技术的结合玩法
5. 等等...
github地址:https://github.com/GerryIsWarrior/ajax 对你有帮助或启发,点个小星星,支持继续研究下去
前端通信:ajax设计方案(十)--- 完善Promise A+规范,增加mock数据功能的更多相关文章
- 按照 Promise/A+ 规范逐行注释并实现 Promise
0. 前言 面试官:「你写个 Promise 吧.」 我:「对不起,打扰了,再见!」 现在前端越来越卷,不会手写 Promise 都不好意思面试了(手动狗头.jpg).虽然没多少人会在业务中用自己实现 ...
- 前端通信:ajax设计方案(五)--- 集成promise规范,更优雅的书写代码(改迭代已作废,移步迭代10)
该迭代已作废,最新的请移步这里:https://www.cnblogs.com/GerryOfZhong/p/10726306.html 距离上一篇博客书写,又过去了大概几个月了,这段时间暂时离开了这 ...
- 前端通信:ajax设计方案(九)--- 完善文档
ajax-js 1.9.1 文档 目录 * common(options, isCreatePoll) * config(options) * get(url, data, successEvent, ...
- 前端通信:ajax设计方案(六)--- 全局配置、请求格式拓展和优化、请求二进制类型、浏览器错误搜集以及npm打包发布
距离上一次博客大概好多好多时间了,感觉再不搞点东西出来,感觉就废了的感觉.这段时间回老家学习驾照,修养,然后7月底来上海求职(面了4家,拿了3家office),然后入职同程旅游,项目赶进度等等一系列的 ...
- 前端通信:ajax设计方案(八)--- 设计请求池,复用请求,让前端通信快、更快、再快一点
直接进入主题,本篇文章有点长,包括从设计阶段,到摸索阶段,再到实现阶段,最后全面覆盖测试阶段(包括数据搜集清洗),还有与主流前端通信框架进行对比PK阶段. 首先介绍一下一些概念: 1. 浏览器的并发能 ...
- 前端通信:ajax设计方案(一)---集成核心请求
报告,我要说话!xp被历史淘汰了,IE6 say goodbye了,太TM开心了,从此不要兼容IE6了,哈哈哈哈哈哈 报告,我要说话!IE这sb为啥不早点被杀掉呢,找工作听说要兼容IE,立马软了,唉唉 ...
- 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- 前端通信:ajax设计方案(三)--- 集成ajax上传技术
在此之前让我感慨一下现在的前端开发的氛围.我遇到好多人,给我的观念都是,这个东西这个框架有了,那个东西那个框架做了,前端嘛,学几个框架,这个拼凑一下那个拼凑一下就好了.其实我想问,东西都框架做了,那你 ...
- 前端通信:SSE设计方案(二)--- 服务器推送技术的实践以及一些应用场景的demo(包括在线及时聊天系统以及线上缓存更新,代码热修复案例)
距离上一篇博客,这篇文章的发布大概过了整整三个月.我也从饿了么度过了试用期,成为了正式员工.刚进来恰好遇到项目底层改造和迁移,将项目从angular全部迁移到vue上,所以适应这边的节奏和业务的开发任 ...
随机推荐
- jar与war包区别,转自https://www.jianshu.com/p/3b5c45e8e5bd
https://www.jianshu.com/p/3b5c45e8e5bd
- <jsp:forward page='/index' />
- MySQL数据查询之单表查询
单表查询 简单查询 - 创建表 DROP TABLE IF EXISTS `person`; CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INCREMEN ...
- tornado框架学习及借用有道翻译api做自动翻译页面
趁着这几天有时间,就简单的学了一下tornado框架,简单做了个自动翻译的页面 仅为自己学习参考,不作其他用途 文件夹目录结构如下: . ├── server.py ├── static │ └─ ...
- 记一次Java Core Dump分析过程
#背景提要 很久没有亲自动手部署代码了,命令行的亲切感越来越低.放飞了键盘,习惯了鼠标操作的windows环境.冷不丁实操部署也是不错的. 常常在部署时,运维同学对于[hs_err_pid]文件视而不 ...
- Spring事务传递
2018-09-25 @Transactional(propagation=Propagation.NEVER) public void update(){ Session s = sessionFa ...
- AX_UserInfo
UserInfoHelp::userInUserGroup(curuserid(), "Admin") EmplTable::userId2EmplId(curuserid()) ...
- 【Mybatis】MyBatis配置文件的使用(二)
本例在[Mybatis]MyBatis快速入门(一)基础上继续学习XML映射配置文件 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properti ...
- innodb_flush_method理解
http://blog.csdn.net/gua___gua/article/details/44916207 innodb_flush_method这个参数控制着innodb数据文件及redo lo ...
- jquery中siblings方法配合什么方法一起使用
siblings() 获得匹配集合中每个元素的同胞,通过选择器进行筛选是可选的.接下来通过本文给大家介绍jQuery siblings()用法实例详解,需要的朋友参考下吧 siblings() 获得匹 ...