从最早的回调函数,之后迎来了 promise,再次就是上篇文章说的 generator,js 解决异步的方案一次次的再优化,ES7 中出现的 Async/await 是目前 js 中异步最终极的解决方案,我的妈耶不谈兼容问题的话,实在是太好用啦。虽然兼容性真的很一般,但是我们可以用 polyfill(js 修补器)去兼容一下呀。接下来我将简单介绍下 Promise、fetch、 Async/await 以及分别用 fetch 和 Async/await 去封装一个增删改查的方法。来看看编写异步代码的过程是如何一步步变得优雅起来的。
Promise
首先我们先来说说 Promise 吧~在 ES6 之前处理异步问题时,我们为了避免操作时的页面中断,通过都是使用回调函数,这时候如果回调函数当中又有回调函数,那么我们就会陷入无尽的回调地狱,代码也变得很难维护。而有了 Promise 对象后,我们就可以很好的解决这个问题,用它的链式调用就可以用同步函数的方式去写异步代码了。简直是造福程序员界一项很牛逼的东西。接下来我们创建一个 Promise 实例。
1 | let promise = new Promise(); |
注意:Promise 构造函数一定要传回调才可以,否则会报错。它接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。
1 | let promise = new Promise((resolve, reject) => { |
我们看到打印出来的是Promise{ < pending > },表示任务在进行中。接下来我将用一张图来看看 Promise 的三种状态和对应的回调。
Promise 的三种状态和对应的回调
虽然这张图我画的有点丑,但是应该也很简单明了的看懂Promise的三种状态,其中我们基本上运用的是resolved和resolved两种状态。
1 | let promise = new Promise((resolve, reject) => { |
我们可以看到,只要前面的reject()成功,后续想调用几个then()方法都可以,这样就不仅仅有一个回调了,有n个回调在等着你。如果异步操作失败了,Promise的转态就会变为rejected,去调用catch方法指定的回调函数处理这个错误。另外,then方法指定的回调函数,如果在运行过程中抛出了错误,也会被catch方法捕获。这里要注意的是:catch返回码超过300就不会打印
Promise 对象特点
1.对象的状态是不受外界影响的
只有异步操作的结果,才可以决定当前是哪一种状态,任何其他的操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
1 | let fulfill = new Promise((resolve,reject) => { |
2.一旦转态改变,转态就会凝固,不再改变
最后的打印结果为:
resolve before
success
resolve 下一句语句是可以执行的,为什么 reject 没有去调用 catch 指定的回调函数呢?这就是因为 Promise 对象的特点:状态的凝固。这个对象从起始的 Pending 状态在根据 resolve 或 reject 返回 Resolved 或 Rejected 状态。
fetch
fetch 是一个基于 promise 的请求方法,更简单便捷。相比与原先在不同浏览器中使用 XMLHttpRequest 对象或者是 ActiveXObject(“x.XMLHTTP”),fetch 方法简化了这一操作。接下来我们用代码看看 fetch 是如何让代码优雅起来的。
fetch 如何优雅于 XMLHttpRequest
1 | //XMLHttpRequest |
1 | //fetch |
从代码上很直观的能看出代码量的减少。fetch 方法返回的是一个 Promise 对象,所以我们可以链式的发起异步请求。http://jsonplaceholder.typicode.com 这个是我做测试经常会用到的网址。从上面的例子可以看出使用 fetch 时第一步 then 返回的是 response 对象。我们需要使用json()方法将将请求回来的 response 对象解析成我们正常可读的对象。这里要注意的是:目前原生的 fetch 还不支持 jsonp 的请求方式,如果需要实现 jsonp,需要安装 npm 包 fetchJ-jsonp
1 |
|
我们在 response 对象上调用 json()方法,返回的依然是一个 Promise 对象,我们需要在下一步的 then()中获得服务器返回的原始对象。接下来我们去请求一个根本没有的域名,模拟一下 catch。
1 |
|
fetch 请求三种数据格式
接下来,我们来实践下如何用 fetch 请求 本地文本数据,本地 json 数据 还有网络接口吧。具体的代码实现效果可以看看实现效果。其中请求本地文本数据采用了 XMLHttpRequest 和 fetch 两种方式。这里展示一部分重要代码。样式没有特意去优化,用的是一个超简单的响应式模板 skeleton。
请求本地文本数据
1 | function getText() { |
请求本地 json 数据
1 | function getJson() { |
请求网络接口
1 | function getWeb() { |
本篇主要介绍记录了 Promise 对象,fetch 如何优雅于 XMLHttpRequest,以及如何用 fetch 请求三种数据数据格式。下一篇中,我们将用 fetch 去封装一个增删改查的方法,以及记录下 JS 最终极的异步解决方案 Async/awai。