ES6 原生提供了 Promise 对象。
所谓 Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

异步方法的各种调用形式

以ajax请求为例

  • ES5正常写法

这种写法缺点如果在回调中还有需要执行的异步方法,容易进入套娃模式。

  1. $.get(url,(res)=>{
  2. //此处执行请求成功的回调
  3. $.get(url2,(res2)=>{
  4. //此处执行请求成功的回调2
  5. ...
  6. ...
  7. })
  8. })
  • Promise写法
  1. getAjax(url).then((res)=>{
  2. //此处执行请求成功的回调
  3. })
  • async_await 写法 ```javascript (async ()=>{ //await等待异步方法的执行,执行成功将响应结果返回 let res = await getAjax(url)

})()

  1. <br />总结:
  2. - ES5写法和promise写法,主要区别在写法的不同,可以让回调函数,划分出去在.then的函数里去执行,使得代码更加的易读,也可以将两个不同的参数,划分开来写。
  3. - async_await和promise的区别,async_await只是promise实现的语法糖而已,这种形式的写法在底层编译之后会自动转化成promise的写法
  4. <a name="BITDI"></a>
  5. ### Promise实现原理(自已实现MyPromise对象)
  6. <a name="VFn9h"></a>
  7. #### 创建类构造对象
  8. ```javascript
  9. class MyPromise{
  10. constructor(fn) {
  11. //将成功的事件函数集成在successList数组里
  12. this.successList = [];
  13. //这里将所有的失败函数集成到failList里
  14. this.failList = []
  15. //pending,fullfilled,rejected
  16. this.state = "pending"
  17. //传入的函数对象,(异步操作的函数内容)
  18. fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
  19. }
  20. }

构造函数的作用:

  • 声明成功函数放置的数组对象
  • 声明失败函数放置的数组对象
  • 定义初始化状态
  • 调用传入进行执行异步内容的函数(在未来有成功的结果时调用传入进去的成功函数,在未来失败时调用传入进行的失败函数)


在MyPromise对象中定义 接收“成功或者失败”时需要调用的函数

将“成功或者失败函数”存放到成功函数队列和失败函数队列中,以便在事件完成时调用。

  1. class MyPromise{
  2. constructor(fn) {
  3. //将成功的事件函数集成在successList数组里
  4. this.successList = [];
  5. //这里将所有的失败函数集成到failList里
  6. this.failList = []
  7. //pending,fullfilled,rejected
  8. this.state = "pending"
  9. //传入的函数对象,(异步操作的函数内容)
  10. fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
  11. }
  12. //then方法接收成功或者失败时需要调用的函数,将函数存放到成功或失败函数队列中
  13. then(successFn,failFn){
  14. if(typeof successFn=='function'){
  15. this.successList.push(successFn)
  16. }
  17. if(typeof failFn=='function'){
  18. this.failList.push(failFn)
  19. }
  20. }
  21. //catch方法接收失败时需要调用的函数,将函数存放到失败函数队列中
  22. catch(failFn){
  23. if(typeof failFn=='function'){
  24. this.failList.push(failFn)
  25. }
  26. }
  27. }

作用:

  • 接收成功和失败的函数放到成功和失败的函数队列里

定义 在事件完成时 调用成功函数和失败函数的 函数(有点绕)

  1. class MyPromise{
  2. constructor(fn) {
  3. //将成功的事件函数集成在successList数组里
  4. this.successList = [];
  5. //这里将所有的失败函数集成到failList里
  6. this.failList = []
  7. //pending,fullfilled,rejected
  8. this.state = "pending"
  9. //传入的函数对象,(异步操作的函数内容)
  10. fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
  11. }
  12. //then方法接收成功或者失败时需要调用的函数,将函数存放到成功或失败函数队列中
  13. then(successFn,failFn){
  14. if(typeof successFn=='function'){
  15. this.successList.push(successFn)
  16. }
  17. if(typeof failFn=='function'){
  18. this.failList.push(failFn)
  19. }
  20. }
  21. //catch方法接收失败时需要调用的函数,将函数存放到失败函数队列中
  22. catch(failFn){
  23. if(typeof failFn=='function'){
  24. this.failList.push(failFn)
  25. }
  26. }
  27. //当事件成功时,执行此函数,此函数会执行成功函数队列中的所有函数
  28. resolveFn(res){
  29. this.state = "fullfilled"
  30. //循环调用成功函数队列中的函数
  31. this.successList.forEach(function(item,index){
  32. //将成功的事件循环调用
  33. item(res)
  34. })
  35. }
  36. //当事件失败时,执行此函数,此函数会执行失败函数队列中的所有函数
  37. rejectFn(res){
  38. this.state = 'rejected'
  39. //循环调用失败函数队列中的函数
  40. this.failList.forEach(function(item,index){
  41. item(res)
  42. })
  43. throw Error(res);
  44. }
  45. }

作用:

  • 成功时调用成功数组里所有的函数,失败时调用失败数组里所有的函数。

应用MyPromise对象

以node中fs模块为例,我们使用MyPromise对象封装一个fs读取文件的方法

引入fs

  1. let fs = require('fs');

封装fsRead方法,读取文件

  1. //例:使用MyPromise对象封装一个fs模块方法
  2. function fsRead(path){
  3. return new MyPromise(function(resolve,reject){
  4. fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
  5. if(err){
  6. reject(err)
  7. }else{
  8. resolve(data)
  9. }
  10. })
  11. })
  12. }

准备需要读取的文件test.txt

  1. 小池
  2. 作者:杨万里
  3. 泉眼无声惜细流,树阴照水爱晴柔。
  4. 小荷才露尖尖角,早有蜻蜓立上头。

调用fsRead方法读取test.txt文件

  1. (async ()=>{
  2. //需要读取的文件路径
  3. let path = './test.txt';
  4. //调用我们使用MyPromise对象封装的fsRead方法异步方法
  5. //Promise写法
  6. fsRead(path).then((data)=>{
  7. console.log("===========Promise写法=============")
  8. console.log(data)
  9. })
  10. //async_await写法
  11. let data = await fsRead(path)
  12. console.log("===========async_await写法=============")
  13. console.log(data)
  14. })()

执行 node node .\mypromise.js控制台输入

  1. PS E:\Workspace_VSCode\node-in-action> node .\promise.js
  2. ===========Promise写法=============
  3. 小池
  4. 作者:杨万里
  5. 泉眼无声惜细流,树阴照水爱晴柔。
  6. 小荷才露尖尖角,早有蜻蜓立上头。
  7. ===========async_await写法=============
  8. 小池
  9. 作者:杨万里
  10. 泉眼无声惜细流,树阴照水爱晴柔。
  11. 小荷才露尖尖角,早有蜻蜓立上头。

完整代码

  1. let fs = require('fs');
  2. class MyPromise{
  3. constructor(fn) {
  4. //将成功的事件函数集成在successList数组里
  5. this.successList = [];
  6. //这里将所有的失败函数集成到failList里
  7. this.failList = []
  8. //pending,fullfilled,rejected
  9. this.state = "pending"
  10. //传入的函数对象,(异步操作的函数内容)
  11. fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
  12. }
  13. then(successFn,failFn){
  14. if(typeof successFn=='function'){
  15. this.successList.push(successFn)
  16. }
  17. if(typeof failFn=='function'){
  18. this.failList.push(failFn)
  19. }
  20. }
  21. catch(failFn){
  22. if(typeof failFn=='function'){
  23. this.failList.push(failFn)
  24. }
  25. }
  26. resolveFn(res){
  27. this.state = "fullfilled"
  28. this.successList.forEach(function(item,index){
  29. //将成功的事件循环调用
  30. item(res)
  31. })
  32. }
  33. rejectFn(res){
  34. this.state = 'rejected'
  35. //注册到的失败所有事件进行调用
  36. this.failList.forEach(function(item,index){
  37. item(res)
  38. })
  39. throw Error(res);
  40. }
  41. }
  42. //例:使用MyPromise对象封装一个fs模块方法
  43. function fsRead(path){
  44. return new MyPromise(function(resolve,reject){
  45. fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
  46. if(err){
  47. reject(err)
  48. }else{
  49. resolve(data)
  50. }
  51. })
  52. })
  53. }
  54. (async ()=>{
  55. //需要读取的文件路径
  56. let path = './test.txt';
  57. //调用我们使用MyPromise对象封装的fsRead方法异步方法
  58. //Promise写法
  59. fsRead(path).then((data)=>{
  60. console.log("===========Promise写法=============")
  61. console.log(data)
  62. })
  63. let data = await fsRead(path)
  64. console.log("===========async_await写法=============")
  65. console.log(data)
  66. })()