一、Promise 特点

  1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
    1. pending: 初始状态,不是成功或失败状态。
    2. resolve/fulfilled: 意味着操作成功完成。
    3. rejected: 意味着操作失败。
  2. 一旦状态改变,就不会再变。
    1. pendding=>resolve/fulfilled;
    2. pendding=>rejected;

二、Promise 优缺点

  1. 优点:
    1. 链式调用,解决回调地狱问题
    2. 指定回调函数的方式更加灵活
  2. 缺点:
    1. 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
    2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
    3. 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

三、主要异步任务

  • Ajax请求
  • setTimeout定时器
  • fs文件流操作等

四、Promise 的简单使用

  1. // fs 异步操作
  2. const fs = require('fs');
  3. const pro_obj = new Promise((resolve, rejects) => {
  4. fs.readFile('./demo.txt', (err, data) => {
  5. if (err) rejects(err);
  6. resolve(data);
  7. });
  8. });
  9. pro_obj.then(
  10. (value) => {
  11. console.log(value.toString());
  12. },
  13. (err) => {
  14. console.log(err);
  15. }
  16. );

五、 Promise API

  1. Promise 构造函数: Promise(excutor){}
    1. executor 函数:执行器 (resolve,reject)=>{}
    2. resolve 函数:内部定义成功时调用的函数 value=>{}
    3. reject 函数: 内部定义失败时调用的函数 reson=>{}

注:执行器函数会在Promise内部同步调用,异步操作再执行器中执行

  1. Promise.prototype.then 方法: (onResolved,onRejected)=>{}
    1. onResolved 函数: 成功的回调函数 (value)=>{}
    2. onRejected 函数:失败的回调函数 (reson)=>{}

注:成功或者失败的回调函数返回的是一个新的Promise对象

  1. Promise.prototype.catch方法: (onRejected)=>{}

    1. onRejected 函数:失败的回调函数 (reson)=>{}
  2. Promise.resolve 方法:(value)=>{}

    1. value:成功的数据或者Promise对象 (返回一个成功/失败的的Promise对象) ```javascript let p1 = Promise.resolve(521)

// 传入的参数为非Promise类型的对象,则返回的结果是成功的Promise对象

console.log(p1) //Promise { 521 }

// 传入的参数为Promise类型的对象,参数的结果决定了resolve的结果

let p2 = Promise.resolve(new Promise((resolve, reject) => {

resolve(‘ok’)

}))

console.log(p2) // Promise { ‘ok’ }

  1. 5. Promise.reject方法:(reson)=>{}
  2. 1. reson 返回失败的原因
  3. ```javascript
  4. let p1 = Promise.reject(521)
  5. console.log(p1) //Promise { <rejected> 521 }
  6. let p2 = Promise.reject(new Promise((resolve, reject) => {
  7. resolve(521)
  8. }))
  9. console.log(p2) //Promise { <rejected> Promise { 521 } }
  10. // 即使是实例对象的回调函数是成功的,reject返回的还是失败的结果
  1. Promise.all 方法:(promises)=>{}
    1. promises:包含n个promise的数组

注:返回一个新的promise,只有所有的promise都成功才算成功,只要一个失败了就直接失败

  1. let p1 = new Promise((resolve, reject) => {
  2. resolve('ok');
  3. });
  4. let p2 = Promise.resolve('success');
  5. let p3 = Promise.resolve('okkkk');
  6. let p4 = Promise.reject('error');
  7. const result = Promise.all([p1, p2, p3]);
  8. const err = Promise.all([p1, p2, p3, p4]);
  9. console.log(result);
  10. console.log(err);

全部成功结果 result:
image.png

有一个失败结果 err:
image.png

  1. Promise.race 方法: (promises)=>{}
    1. promises:包含n个promise的数组

注:返回一个新的promise对象,是第一个成功的的promise的结果状态

  1. let p1 = new Promise((resolve, reject) => {
  2. reject('ok');
  3. });
  4. let p2 = Promise.reject('success');
  5. let p3 = Promise.resolve('okkkk');
  6. const result = Promise.race([p1, p2, p3]);
  7. console.log(result);

六、Promise关键问题

1. 修改Promise状态的方法
  1. 执行reject方法 pending=> reject
  2. 执行resolve方法 pending =>resolve
  3. 丢出错误throw pending=>reject

code1.png

2.能否执行多个回调

当promise状态改变时,它所定义的多个成功/失败的回调函数都会执行

3.改变promise的状态和指定回调函数谁先谁后(resolve、reject先执行还是then、catch先执行)
  1. 都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调(看执行器内部的任务队列是同步任务还是异步任务,)
  2. 如何先改变状态再指定回调
    1. 在执行器中直接调用resolve或者reject
    2. 延迟更长时间才调用then()
  3. 什么时候拿到数据

    1. 如果先指定的回调,那么当状态改变时,回调函数就会调用,就能得到数据
    2. 如果先改变的状态,那当指定回调是,回调函数就会调用,得到数据
      4.Promise then 方法的返回的新的promise的结果状态由什么决定?
  4. 简单表达: 由then方法指定的回调函数执行的结果决定

  5. 详细表达:
    1. 如果抛出异常,新的Promise变为rejected,reson为抛出的异常
    2. 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
    3. 如果返回的是另外一个新的Promise ,此promise的结果就会成为新的promise的结果
      5. Promise如何串联多个操作任务
      可以写成then方法的链式调用(原理:promise的then方法返回的还是promise对象)
  1. code.png
    6. Promise 异常穿透
    当使用promise的then的链式调用时,可以在最后指定失败的回调函数catch,当前面任何操作出了异常都会被传到追后失败的回调中处理

7. 中断promise链

当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。方法:在回调函数中返回一个pendding状态的promise对象

七、手写源码

  1. /**
  2. * 1. 搭建Promise基础架构
  3. * a.Promise接受executor作为参数传入
  4. * b.设置内置属性[PromiseStatus、PromiseResult]和方法[resolve、reject]
  5. * Ⅰ. PromiseStatus有三种状态,分别为pending,fulfilled,rejected,状态只能改变一次,pending=>fuifilled pending=>rejected
  6. * Ⅱ. PromiseResult 执行的结果保存在PromiseResult中
  7. * c. 使用try catch来获取executor中抛出的错误,并返回Promise对象处理抛出的异常
  8. * 2. then方法
  9. * a. then方法执行回调函数需要有条件,根据状态执行对应的回调函数,函数的实参是存储在PromiseResult的值
  10. * b. 处理异步状态,实例对象内部为异步函数,状态是pending ,then方法的回调没有等到pending状态的改变,导致then方法不执行,解决方法:定义callbacks回调数组
  11. * 3. 实现catch方法
  12. * 4. 实现resolve、reject方法
  13. * 5. 实现all、race方法
  14. *
  15. * @param {*} executor
  16. */
  17. function Promise(executor) {
  18. this.PromiseStatus = 'pending';
  19. this.PromiseResult = null;
  20. this.callbacks = [];
  21. resolve = (data) => {
  22. if (this.PromiseStatus !== 'pending') return;
  23. this.PromiseResult = data;
  24. this.PromiseStatus = 'fulfilled';
  25. // 复现原生Promise的异步调用机制
  26. setTimeout(() => {
  27. this.callbacks.forEach((item) => item.onResolved(data));
  28. });
  29. };
  30. reject = (data) => {
  31. if (this.PromiseStatus !== 'pending') return;
  32. this.PromiseResult = data;
  33. this.PromiseStatus = 'rejected';
  34. // 复现原生Promise的异步调用机制
  35. setTimeout(() => {
  36. this.callbacks.forEach((item) => item.onRejected(data));
  37. });
  38. };
  39. try {
  40. executor(resolve, reject);
  41. } catch (error) {
  42. reject(error);
  43. }
  44. }
  45. Promise.prototype.then = (onResolved, onRejected) => {
  46. // 异常穿透
  47. if (typeof onResolved !== 'function') {
  48. onResolved = (data) => data;
  49. }
  50. if (typeof onRejected !== 'function') {
  51. onRejected = (reason) => {
  52. throw reason;
  53. };
  54. }
  55. return new Promise((resolve, reject) => {
  56. const callback = (type) => {
  57. try {
  58. let result = type(this.PromiseResult);
  59. if (result instanceof Promise) {
  60. result.then(
  61. (r) => resolve(r),
  62. (j) => reject(j)
  63. );
  64. } else {
  65. resolve(result);
  66. }
  67. } catch (error) {
  68. reject(error);
  69. }
  70. };
  71. if (this.PromiseStatus === 'fulfilled') {
  72. callback(onResolved);
  73. }
  74. if (this.PromiseStatus === 'rejected') {
  75. callback(onRejected);
  76. }
  77. if (this.PromiseStatus === 'pending') {
  78. this.callbacks.push({
  79. onResolved: callback(onResolved),
  80. onRejected: callback(onRejected),
  81. });
  82. }
  83. });
  84. };
  85. Promise.prototype.catch = function (onRejected) {
  86. return this.then(undefined, onRejected);
  87. };
  88. Promise.resolve = function (value) {
  89. return new Promise((resolve, reject) => {
  90. if (value instanceof Promise) {
  91. value.then(
  92. (r) => {
  93. resolve(r);
  94. },
  95. (j) => {
  96. reject(j);
  97. }
  98. );
  99. } else {
  100. resolve(value);
  101. }
  102. });
  103. };
  104. Promise.reject = function (value) {
  105. return new Promise((resolve, reject) => {
  106. reject(value);
  107. });
  108. };
  109. Promise.all = function (pArray) {
  110. return new Promise((resolve, reject) => {
  111. let count = 0;
  112. let pResult = [];
  113. for (let i = 0; i < pArray.length; i++) {
  114. pArray[i].then(
  115. (v) => {
  116. count++;
  117. pResult[i] = v;
  118. if (count === pArray.length) {
  119. resolve(pResult);
  120. }
  121. },
  122. (j) => {
  123. reject(j);
  124. }
  125. );
  126. }
  127. });
  128. };
  129. Promise.race = function (pArray) {
  130. return new Promise((resolve, reject) => {
  131. for (let i = 0; i < pArray.length; i++) {
  132. pArray[i].then(
  133. (r) => {
  134. resolve(r);
  135. },
  136. (j) => {
  137. reject(j);
  138. }
  139. );
  140. }
  141. });
  142. };