实用主义:Promise让异步回调更加优雅
前言
函数作为一等对象,使得javascript这种弱类型,单线程脚本语言的异步方法极为方便,只需要一个callback,编译器就能按照我们的想法执行命令。如果只有一个简单的异步操作,我们可以稍费脑子理清执行顺序,但是如果有多个异步方法,呃,我们就可能掉进了回调陷阱,事情远远没有我们想到的那么简单,并且我们甚至还没考虑过异步中抛出的错误。
还好Promise的出现,解救了我们,这篇文章不是讲解Promise的详细使用方法,只是通过两个例子,看看Promise的优雅之处,详细资料请参考阮一峰老师 《ES6标准入门》
传统的ajax回调
代码运行于最新的Chrome版本中,Chrome目前已支持除 模块 以外的大部分ES6方法
let xhr = new XMLHttpRequest();
let url = 'http://chat.hstar.org:8601/rkyNA2Yvl/promise';
xhr.responseType = "text";
xhr.open('get', url, true);
xhr.onreadystatechange = ((data) => {
if (xhr.readyState===4 && xhr.status===200) {
let data = JSON.parse(xhr,responseText);
console.log(data.word);
}
});
xhr.send(null);
结果
这是一个传统的ajax回调,我们把所有事务逻辑封装在onreadystatechange
事件中,并且xhr的生成与使用都在一块代码内。后期的维护、DOM操作都只能该事件中进行,这只是一个异步事件,如果是多个异步事件,并且需要所有事件都能完成才能操作。Oh my god。我们可能已经进入回调地狱。这团代码在后期debug时候足以让我们抓狂。
Promise的出现
我们再来看看一段经过Promise封装的代码
function getPromise(url) {
let p = new Promise((resolve,reject) => {
let xhr = new XMLHttpRequest;
xhr.open('get', url, true);
xhr.onreadystatechange = () => {
if (xhr.status == 200 && xhr.readyState===4 ){
resolve(xhr.responseText);
}
};
xhr.onerr = function () {
reject();
}
xhr.send(null);
});
return p;
}
首先封装一个Promise对象,我们把响应事件封装在resolve
方法中,如果仅仅是这样,那么和普通封装没有区别,我们接着来看看Promise的优雅之处
let promise = getPromise('http://chat.hstar.org:8601/rkyNA2Yvl/promise');
promise.
then(data => {
data = JSON.parse(data);
return data;
}).then(data => {
document.write(data.word);
console.log(data);
}).catch(err => {
console.log(err);
});
结果
我们通过then(resolve方法的别名),进行回调操作,then方法返回的也是一个Promise对象,因此可以链式调用,这样我们可以按步骤操作返回的数据。并且catch方法会捕捉每一个异步方法中的错误,所有的错误都会冒泡到这里,如果catch方法出现了错误怎么办?别担心done()方法会处理最后的错误。 通过这样的链式调用,使得 关注点 分离,return的形式也更符合人脑的思考逻辑。 前面还提到了多个异步操作,我们同样可以使用Promise.all和Promise.race方法。
最后
相比传统的ajax方法,Promise的优雅之处在于
- 关注点分离,每一次调用只需要完成一个任务;
- 更符合人脑思考逻辑;
- 良好的错误处理逻辑,错误冒泡;
- all() 和 race()方法避免陷入回调地狱
这里仅仅是简单封装了XMLHttpRequest方法,随着JS的发展,fetch axios vue-resource等新一代ajax方法都已经实现了对Promise的封装,这里也该大家分享一段我们项目对Promise的深度封装实现(基于axios)
基于axios的封装
所以大家也快来拥抱ES6的新特性吧 就是这样:)
- Linux下性能调试工具-top和sar运维笔记
- Apache+wsgi+flask部署
- “勒索病毒”到底会勒索啥,尽可以做到让全球对之恐惧无奈!
- 解决win10 关键错误开始菜单和cortana无法工作 的问题(转-真的成功了)
- “AS3.0高级动画编程”学习:第二章转向行为(下)
- windows系统中eclipse C开发环境的架设
- 5个酷毙的Python工具
- ”盒模型“之如何防止边框和内边距把元素撑开
- excel中的不同类型图表叠加
- 这几天遇到的关于IE6/sql2008/win2003的奇怪bug
- 基于Web的工作流管理系统的设计与实现
- 这是对position讲解最通俗易懂的版本了。
- 你到底该如何看待比特币?
- OpenApplus小程序容器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法