Promise是?

  • es6之前,js解决异步的方案是 回调函数,这会带来一系列的问题,尤其是回调里嵌套回调导致的回调地狱;

如:

  1. // 定义一个1s后执行callback的异步api
  2. function late1sCallback(callback){
  3. setTimeout(callback,1000);
  4. }
  5. //感受下回调地狱吧!凡人!
  6. late1sCallback(function(){
  7. late1sCallback(function(){
  8. late1sCallback(function(){
  9. console.log('这是一个打印,目测约在3s后执行');
  10. })
  11. })
  12. })

于是社区就有了对应的封装解决方案,基于callback这种形式封装了一个Promise类,用起来比较方便,解决了上面的问题。
再于是乎,定义ES规范的大人物们觉得还不错,就在ES6把Promise给规范了(就是内置了Promise类)。

new Promise 与 .then属性

  • 那么我们先学习Promise的简单使用 new Promise与 .then:

    1. new Promise(late1sCallback) // 返回一个promise对象
    2. .then(()=>{
    3. console.log('这是一个打印,目测1s后执行')
    4. })
    5. .then(()=>{
    6. console.log('这是一个打印,上一个执行完了这个才会执行')
    7. })

    ok,我们到这能看到,其实Promise就是把callback参数的形式放到了 .then里;
    并且.then后能够继续.then,这叫做链式调用,我们之前讲过它的实现,无非是返回了一个promise对象;

  • 那么我们试图封装它:
    ```javascript // 这里一共用了四行代码,实现了这种形式的异步api封装
    function MyPromise(asyncFn){ this.then = function(callback){ // callback就是resolve

    1. asyncFn(callback);
    2. return this; // this就是Promise实例化对象

    } }

// 试一试 function late1sCallback(callback){ setTimeout(callback,1000); }

new MyPromise(late1sCallback) .then(function(){console.log(1)}) .then(function(){console.log(2)})

  1. 那么Promise我们就简单的封装完了,虽然只实现了.then功能,并且有一定缺陷(没有队列控制,没有容错,没有参数传递等);<br />当然,promise对象不可能只有一个.then功能,那么我们将深入学习下promise
  2. <a name="5vsue"></a>
  3. ### Promise.resolve
  4. `**Promise.resolve(value)**`方法返回一个以给定值解析后的[`Promise`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise) 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是thenable(即带有[`"then" `](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。<br />上述看起来不好理解?没关系,看下面的代码:
  5. ```javascript
  6. const promise = Promise.resolve(2);// 这个api接受一个值作为参数,返回的是一个promise对象
  7. promise.then(value =>console.log(value));
  8. //打印2 也就是说,上面的参数值会作为第一个.then的形参。 当然.then也会返回一个promise对象。
  9. // 因此它们都可以链式调用
  10. Promise.resolve(5)
  11. .then(value=>{
  12. console.log(value); //5
  13. return value +1; // 返回值作为下一个.then的形参
  14. })
  15. .then(data=>console.log(data)) // 6

然后是关于 thenable参数的解读。 意思是如果传入的参数,含有.then的属性(它有可能是一个promise对象,也有可能是一个含有.then属性的普通对象),比如:

  1. // 案例1
  2. Promise.resolve({
  3. then:(callback,failCallback)=>{
  4. callback('嘿嘿')
  5. }
  6. }) // 传入了一个含有.then属性的对象
  7. .then(console.log) // 嘿嘿
  8. // 案例2
  9. const p = new Promise(function(callback){
  10. callback('哈哈')
  11. })
  12. Promise.resolve(p)
  13. .then(console.log) // 哈哈

要注意的是 如果promise.resolve的参数值是一个thenable,那么它的resolve是一个异步的( 因为.then的callback是异步执行的 )。

Promise.all

试想这样一个场景,某个页面级组件可能要在初始化后请求多个接口,并且要等所有请求返回后才更新数据, 且任何一个接口请求失败,就要阻止数据更新操作,那么Promise.all就用的上了。
它的参数是一个数组,每一项是一个promise值(就是所谓的resolve,其实就是一个值,或者promise对象);
它的返回值是一个 promise_resolve的数组

  1. const p_1 = new Promise((resolve,reject)=>{
  2. setTimeout(()=>{
  3. resolve('p1')
  4. }),2000
  5. });
  6. const p_2 = Promise.resolve('p2');
  7. const p_3 = Promise.resolve({
  8. then:(resolve)=>{
  9. resolve('p3');
  10. }
  11. });
  12. const p_4 = 'p4';
  13. Promise.all([p_1,p_2,p_3,p_4])
  14. .then(console.log) // 打印 ["p1", "p2", "p3", "p4"]
  15. .catch(console.log)
  16. // 当某一个发生error
  17. const p_5 = Promise.resolve({
  18. then: (resolve,reject)=>{
  19. throw new Error('p_5error');
  20. resolve('p_5');
  21. }
  22. })
  23. const p_6 = Promise.resolve({
  24. then: (resolve,reject)=>{
  25. reject('p_6error');
  26. resolve('p_6')
  27. }
  28. })
  29. Promise.all([p_2,p_5])
  30. .then(console.log) //不会执行这句
  31. .catch(console.log) // Error
  32. Promise.all([p_2,p_6])
  33. .then(console.log) //不会执行这句
  34. .catch(console.log) // p_6error

当然,正是由于Promise.all这样的设计,所以某些场景下(与上述的场景要求不同)它反而会起不好的作用:
比如 我们的页面组件 需要同时发送多个请求,如果用promise.all 的话,有一个请求失败 那么所有后续操作(
就是Promise.all之后的.then )都会挂掉。

Promise.race

Promise.race 正如其名,race(赛跑)。
它的参数与Promise.all是一致的 => 都是一个resolve值组成的数组;
它的返回值是数组中最快的那个返回的promise对象

  1. const p1 = new Promise((resolve)=>{resolve('p1')});
  2. const p2 = 'p2';
  3. const p3 = Promise.resolve('p3');
  4. Promise.race([p1,p2,p3])
  5. .then(console.log) // p1 因为都不是异步,顺序执行,p1最先
  6. const p4 = new Promise((resolve)=>{
  7. setTimeout(()=>{
  8. resolve('p4')
  9. })
  10. })
  11. Promise.race([p4,p2])
  12. .then(console.log) // p2 因为p2执行顺序优先
  13. const p5 = Promise.resolve({
  14. then:(resolve,reject)=>{
  15. reject('被catch的p5')
  16. }
  17. })
  18. Promise.race([p5,p4])
  19. .then(console.log)
  20. .catch(console.log) // 被catch的p5

Promise的执行顺序

  1. const p1 = new Promise(resolve=>{
  2. setTimeout(()=>{
  3. console.log('p1的函数执行了');
  4. resolve('p1的resolve值');
  5. },300)
  6. })
  7. const p2 = Promise.resolve('p2');
  8. setTimeout(()=>{
  9. console.log('这是一个0s的setTimeout')
  10. },0)
  11. const p3 = Promise.resolve({
  12. then:(resolve)=>{
  13. console.log('p3的thenable执行了')
  14. resolve('p3')
  15. }
  16. })
  17. const p4 = new Promise((resolve)=>{
  18. console.log('p4的函数执行');
  19. resolve('p4');
  20. })
  21. const p5 = new Promise((resolve)=>{
  22. setTimeout(()=>{
  23. console.log('p5的函数开始执行了');
  24. resolve('p5');
  25. })
  26. })
  27. Promise.race([p1]).then(value=>console.log(`
  28. [p1]的race结果: ${value}
  29. `))
  30. Promise.all([p1,p2,p3,p4]).then(console.log)
  31. Promise.race([p1,p2,p3,p4]).then(value=>console.log(`
  32. [p1,p2,p3,p4]的race结果: ${value}
  33. `))
  34. Promise.race([p1,p3]).then(value=>console.log(`
  35. [p1,p3]的race结果: ${value}
  36. `))
  37. Promise.race([p3,p4]).then(value=>console.log(`
  38. [p3,p4]的race结果: ${value}
  39. `))
  40. Promise.race([p4]).then(value=>console.log(`
  41. [p4]的race结果: ${value}
  42. `))
  43. p5.then(value=>console.log(`p5.then => ${value}`))
  44. p1.then((value)=>console.log(`p1.then => ${value}`));
  45. p3.then((value)=>console.log(`p3.then => ${value}`))
  46. //p4的函数执行
  47. // p3的thenable执行了
  48. // p3.then => p3
  49. //[p1,p2,p3,p4]的race结果: p2
  50. //[p3,p4]的race结果: p4
  51. //[p4]的race结果: p4
  52. //[p1,p3]的race结果: p3
  53. // 这是一个0s的setTimeout
  54. // p5的函数开始执行了
  55. // p5.then => p5
  56. // p1的函数执行了
  57. // p1.then => p1的resolve值
  58. // [p1]的race结果: p1的resolve值
  59. // ["p1的resolve值", "p2", "p3", "p4"]

封装Promise类

  1. class MyPromise{
  2. constructor(fn){
  3. this.PromiseStatus = 'pedding';
  4. this._ProxyStatus = this.PromiseStatus;
  5. this.PromiseValue = undefined;
  6. this.resolvedCallbackList= [] ;
  7. this.failCllbackList = [];
  8. this.currentCall ={
  9. type: null,
  10. Index: -1
  11. }
  12. // this.promiseValue发生变化就执行这个;
  13. this.callThen = ()=> {
  14. if(!this.resolvedCallbackList.length){
  15. return null;
  16. }
  17. this.PromiseStatus = 'pedding';
  18. try{
  19. this.PromiseValue = this.resolvedCallbackList[0](this.PromiseValue);
  20. this.PromiseStatus = 'resolved';
  21. }catch(error){
  22. this.PromiseValue = error;
  23. this.PromiseStatus = 'fulfilled';
  24. }
  25. }
  26. this.then = (resolvedCallback) => {
  27. this.resolvedCallbackList.push(resolvedCallback);
  28. if(this.PromiseStatus==='resolved'){
  29. this.callThen();
  30. }
  31. return this;
  32. }
  33. this.catch = (failCallback) => {
  34. this.failCllbackList.push(failCallback);
  35. if(this.PromiseStatus==='fulfilled'){
  36. this.failCllbackList[0](this.PromiseValue);
  37. }
  38. return this;
  39. }
  40. Object.defineProperty(this,'PromiseStatus',{
  41. get: value => {
  42. return this._ProxyStatus;
  43. },
  44. set:(value)=>{
  45. this._ProxyStatus = value;
  46. if(value === 'resolved') {
  47. this.resolvedCallbackList.shift();
  48. this.callThen();
  49. }
  50. if(value === 'fulfilled') {
  51. this.failCllbackList[0]&&this.failCllbackList[0](this.PromiseValue);
  52. }
  53. }
  54. })
  55. try{
  56. this.resolvedCallbackList.push(fn);
  57. fn(value=>{
  58. this.PromiseValue = value;
  59. this.PromiseStatus = 'resolved';
  60. this.currentCall ={
  61. type: 'resolvedCallbackList',
  62. Index: 0
  63. }
  64. });
  65. }catch(error){
  66. this.PromiseValue = error;
  67. this.PromiseStatus = 'fulfilled';
  68. this.currentCall ={
  69. type: 'failCllbackList',
  70. Index: 0
  71. }
  72. }
  73. }
  74. }
  75. // 使用 1
  76. new MyPromise((resolve)=>{
  77. resolve(2);
  78. })
  79. .then(console.log)
  80. // 使用 2
  81. new MyPromise(resolve=>{
  82. setTimeout(()=>{
  83. console.log('setTimeOut执行');
  84. resolve(0);
  85. })
  86. })
  87. .then(value=>{
  88. console.log('第一个.then的callback')
  89. return value+1;
  90. })
  91. .then(value => {
  92. console.log('第二个.then');
  93. return value+1;
  94. })
  95. .then(console.log)
  96. // 使用 3 测试catch功能
  97. new MyPromise((resolve)=>{
  98. setTimeout(()=>{
  99. console.log('use3')
  100. resolve('44')
  101. },600)
  102. })
  103. .then(()=>{console.log('1then')})
  104. .then (()=>{
  105. throw new Error('这是一个error')
  106. })
  107. .then(()=>console.log('2then'))
  108. .catch(console.log)

代码力的体现。

Promise的扩展学习

学习一个函数,我们需要从它的参数和返回值开始;
学习一个构造函数(类),还要学习它的实例挂载的属性和方法;
点击下面链接学习Promise:
es6Promise链接