浅谈Promise语法API+封装
为了解决回调地狱callback fell嵌套带来的问题,ES6新增了一个API:Promise(译为承诺保证),本质为“构造函数”
注意:Promise是ES6新增的方法,与node无关,在浏览器端也可以执行
(1)分析
Promise可以理解为一个容器,容器里放了一个异步任务,默认异步任务分为3种状态
1、pending译为(在...期间),表示正在进行的状态,默认便是pending正在执行状态。例如读取文件,默认为正在读... ...
接下来pending只能变成两种状态:“完成”or“失败”
2、resolved译为(成功、已解决),表示任务成功
3、rejected译为(失败、驳回、拒绝),表示任务失败
注意:状态是不可逆的.
(2)Promise代码编写
1、新建文件demo-promise.js,用来编写执行promise相关API
首先明确一点,Promise是ES6新语法,不是node独有的,浏览器亦可执行,如下所示
返回构造函数,接下来看下如何使用。
2、创建Promise容器
3、容器中一般放置异步任务,里面传一个函数作为参数
4、Promise不是异步,但Promise承诺容器里的任务一定是异步的,验证如下
执行结果如下
由此可知Promise承诺不是异步的,因为2在1后面,在4前面。而Promise承诺容器里的任务是异步的
注意:
5、接下来pending状态要转变成“resolved成功”或者“rejected失败”状态
首先传入形参resolve和reject
然后改变状态
接下来将Promise容器实例绑定到变量,建立引用关系
6、变量实例调用then方法
做个简单验证
分析:也就是说这里调用的resolve方法实际上就是then方法传递的那个function
接下来传入data即可获取读取文件成功后返回的结果
7、then方法第二个参数函数
调用reject就相当于调用了then方法的第二个参数函数
接下来可以做个简答验证,修改文件路径为错误路径
目前为止只关注Promise语法部分,还没有涉及解决回调地狱问题
语法解析:
1、通过new Promise创建承诺容器,在内部执行异步操作,传入参数resolve和reject。成功时调用resolve(data),pending进行中状态更改为成功。失败调用reject(error),
传入错误对象,状态更改为失败; 2、如何获取成功或失败的数据呢??? 方法:通过Promise实例对象的then方法,接收两个参数函数,第一个为成功函数参数对应之前的resolve(data),第二个为失败函数对应之前的reject(error)
8、完整代码的图例分析
(3)解决嵌套问题
1、接下来再新建两个Promise实例
2、二次then方法
接下来再次调用then方法,接收第一个then成功函数返回值,验证如下
如果第一个then参数函数,没有return返回值,则返回undefined,接着修改
注意:
当这里return一个Promise即p2时,后续的then中方法的第一个参数会作为p2的resolve成功函数,验证如下
接着读取p3,如下所示
这里便是then方法的链式调用,验证如下
总代码如下:
代码结构图:
3、缺点
目前为止可以通过promise实例的then方法链式调用解决回调嵌套问题。但仍有不足,如下所示:代码重复率较高,封装性不好,
所以接下来封装Promise,即new Promise创建承诺容器可以进一步封装
(4)总结
最后,对比代码如下
回调地狱方法:
var fs = require('fs') fs.readFile('./a.txt','utf8',function(error,data){ if(error){ /*return console.log('读取失败')*/ /*另外,也可以手动抛出异常,阻止程序执行且返回错误信息到控制台*/ throw error } console.log(data) fs.readFile('./b.txt','utf8',function(error,data){ if(error){ /*return console.log('读取失败')*/ /*另外,也可以手动抛出异常,阻止程序执行且返回错误信息到控制台*/ throw error } console.log(data) fs.readFile('./c.txt','utf8',function(error,data){ if(error){ /*return console.log('读取失败')*/ /*另外,也可以手动抛出异常,阻止程序执行且返回错误信息到控制台*/ throw error } console.log(data) }) }) })
Promise方法:
var fs = require('fs') var p1 = new Promise(function(resolve,reject){ fs.readFile('./a.txt','utf8',function(error,data){ if(error){ reject(error) }else{ resolve(data) } }) }) var p2 = new Promise(function(resolve,reject){ fs.readFile('./b.txt','utf8',function(error,data){ if(error){ reject(error) }else{ resolve(data) } }) }) var p3 = new Promise(function(resolve,reject){ fs.readFile('./c.txt','utf8',function(error,data){ if(error){ reject(error) }else{ resolve(data) } }) }) /*读取*/ p1 .then(function(data){ console.log(data) return p2 },function(error){ console.log('读取a文件失败'+error) }) .then(function(data){ console.log(data) return p3 },function(error){ console.log('读取b文件失败'+error) }) .then(function(data){ console.log(data) },function(error){ console.log('读取c文件失败'+error) })
结果:
(5)封装Promise版本的readFile
var fs = require('fs') function promiseReadFile(filePath){ return new Promise(function(resolve,reject){ fs.readFile(filePath,'utf8',function(error,data){ if(error){ reject(error) }else{ resolve(data) } }) }) } promiseReadFile('./a.txt') .then(function(data){ console.log(data) return promiseReadFile('./b.txt') }) .then(function(data){ console.log(data) return promiseReadFile('./c.txt') }) .then(function(data){ console.log(data) })
.