前言
ES6已经出了好几年,最近才逐渐开始学ES6甚是愧疚;提起ES6,相信大部分人第一时间想起的是Promise,Promise一出场就是牛逼之气充斥天地,如狼似虎放荡不羁,在前端技术高速更新的这年代不学Promise还真不好意思在别人面前说会异步;刚开始学Promise的时候真是一头雾水,完全不懂为什么社区要提出这种异步解决方案,直至前前后后读了五六次阮一峰老师写的ES6入门中的Promise章节才有点明白为什么Promise会是Promise,
书读百遍,其义自见
,每次看Promise都会有不同的收获,沉淀了一个月,我觉得自己对Promise也有了一定的了解,是时候写篇博客了。
回调地狱
|
|
暑假的时候也用Node写了点异步回调,但回调很深,看着很难受,就像这仅仅是三层回调嵌套就已经开始恶心了,继续增加回调不仅维护难,更是增加心智压力,看看Promise的写法
|
|
顿时那种累赘烦杂的感觉就没了,仿佛在写同步一样,心智压力大减;那好,现在开始讲Promise
Promise是什么
- 看了那么多与Promise有关的博客或文章,发现都大同小异,写得比较好的还是阮一峰老师的,所以这里就概括一下阮一峰老师写的Promise再加上自己的一些见解:
Promise是个对象,但简单点说它是一个容器,装着的是异步操作的结果(成功或失败),也可称为状态机;Promise对象有两个特点,1、
对象的状态不受外界影响
:Promise代表着一个异步操作,有三种状态:pending(进行中)
、resolved(成功)
、rejected(失败)
,除异步操作,外界无法改变这个状态;2、一旦状态改变,就不会再变
:意思是如果一旦确定Promise是什么状态,resolved
或rejected
,就凝固当前状态,不会再发生改变。
怎样写Promise
|
|
如上所示就是一个简单的Promise例子,上面说过,Promsie本身就是一个对象,所以会用到
new
来生成它,Promise的构造函数需要传入两个参数resolve
和reject
,这两个参数分别是函数,当异步操作结束后,把结果传出去,resolve
传的是成功后的结果,reject
传的是操作失败报错;而调用则用then
来表示:
|
|
then
也可以接收一个或两个参数,第一个参数是执行成功后的调用,即构造Promise对象时传入resolve
的结果,第二个参数是执行失败的调用,即构造Promise是reject
传入的报错;也可以只有一个参数,用来执行成功后的调用,但是要在then
后面用catch
捕捉错误,不然不会返回错误信息,用catch
的好处是,不管有多少个then
,只要有一个catch
就可以捕捉以上的所有错误信息,不必每个then
里面都带第二个错误参数。
123456789 promise().then(A => {return other Promise}).then(B => {return another Promise}).then(C => {//something}).catch(err => {console.log(err);})这里采用的是链式结构,每次调用
then
里都返回一个新的Promise对象,最后用catch
将上面可能抛出的错误捕捉,是一种近似同步的写法
- 经典实例:1234567891011121314151617181920212223242526272829const getJSON = function(url) {const promise = new Promise(function(resolve, reject){const handler = function() {if (this.readyState !== 4) {return;}if (this.status === 200) {resolve(this.response);} else {reject(new Error(this.statusText));}};const client = new XMLHttpRequest();client.open("GET", url);client.onreadystatechange = handler;client.responseType = "json";client.setRequestHeader("Accept", "application/json");client.send();});return promise;};getJSON("/posts.json").then(function(json) {console.log('Contents: ' + json);}, function(error) {console.error('出错了', error);});
实现Ajax操作可以说是应用
Promise
较多的地方,基本我看的每篇与Promise
相关的博客里都会用到实现Ajax操作一实例,在这个实例中,getJSON
对XMLhttpRequest对象封装,在现实Promise
的时候将数据加载到XMLHttpRequest中,更是给Promise
返回了resolve
和reject
。Promise.all 和 Promise.race
Promise.all
:用来将多个Promise实例包装成一个新的Promise实例,接收的参数是一个数组,Promise.all([])
,返回的resolve
里的结果也是一个数组。唯有等参数中所有的Promise
都执行完成后才会执行then
,也唯有所有的Promise
都是resolve
才是resolve
。Promise.race
:同样是用来将多个Promise实例包装成一个新的Promise实例,和Promise.all
唯一不同的是,一旦参数中的Promise
完成,整个Promise
就以第一个完成的状态走下去。
结语
Promise
的内容还有很多,上面写这些只是写基础的,阮一峰老师写的ES6真是经典,值得我辈精读!结尾引用一只诚信肥宅写的骚操作,渲染html至md:12345678910111213141516171819202122232425262728293031323334353637const fs = require('then-fs'), dist = '/home/myblog', src = '/home/myblog-markdown', path = require('path')// render 可以渲染 markdwon 字符串, render = require('./render')fs.readdir(src).then(files => {// 文件夹下有 a.md 和 b.md 将其 map 成绝对路径:// /home/myblog-markdown/a.md 和 /home/myblog-markdown/b.mdreturn files.map(e => path.join(src, e))}).then(files => {// 这里是绝对路径let readAllFiles = files.map(file => {return fs.readFile(file).then(data => {let html = render(data.toString());return {html: html,filePath: file.replace('.md', '.html')}});});return Promise.all(readAllFiles)}).then(htmlDatas => {let saving = htmlDatas.map(data => {let { html, filePath } = data;return fs.writeFile(filePath, html);});return Promise.all(saving);}).then(allDone => {console.log('All Success')}).catch(err => {console.log(err);})
https://eczn.coding.me/blogs/fc68a92a80335f1c38d81f77e4852e61/