《Promise》

1、初识Promise

Promise 是异步操作的一种解决方案
Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题

1.1、Promise的基本用法

实例化构造函数生成实例对象
Promise 的状态 :Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
Promise 的状态一旦变化,就不会再改变了
resolve 和 reject 函数的参数

const p = new Promise((resolve, reject) => {
      reject(new Error('reason'));
    });
    p.then(
      data => {
        console.log('success', data);
      },
      err => {
        console.log('error', err);
      }
    );

    console.log(p);

2、 Promise的构造函数方法

Promise.resolve是成功状态 Promise 的一种简写形式.

//下面两种写法相同
new Promise(resolve => resolve('foo'));
Promise.resolve('foo');

参数
一般参数

    Promise.resolve('foo').then(data => {
        console.log(data);
      });

Promise对象:当 Promise.resolve() 接收的是 Promise 对象时,直接返回这个 Promise 对象,什么都不做

  const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
        // setTimeout(() => {
        //   resolve('我执行了');
        // }, 1000);
      });
      Promise.resolve(p1).then(data => {
        console.log(data);
      });
      // 等价于
      p1.then(data => {
        console.log(data);
      });
      console.log(Promise.resolve(p1) === p1);

当 resolve 函数接收的是 Promise 对象时,后面的 then 会根据传递的 Promise 对象的状态变化决定执行哪一个回调

 new Promise(resolve => resolve(p1)).then(data => {
        console.log(data);
  });

具有then方法的对象

 const thenable = {
        then(resolve, reject) {
          console.log('then');
          resolve('data');
          // reject('reason');
        }
      };
      Promise.resolve(thenable).then(
        data => console.log(data),
        err => console.log(err)
      );
      console.log(Promise.resolve(thenable));

Promise.reject() 失败状态 Promise 的一种简写形式

new Promise((resolve, reject) => {
        reject('reason');
      });
      等价于
      Promise.reject('reason');

不管什么参数,都会原封不动地向后传递,作为后续方法的参数

 const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
      });
      Promise.reject(p1).catch(err => console.log(err));

      new Promise((resolve, rejcet) => {
        resolve(123);
      })
        .then(data => {
          // return data;
          // return Promise.resolve(data);

          return Promise.reject('reason');
        })
        .then(data => {
          console.log(data);
        })
        .catch(err => console.log(err));

Promise.all()关注多个 Promise 对象的状态变化,传入多个 Promise 实例,包装成一个新的 Promise 实例返回

Promise.all() 的状态变化与所有传入的 Promise 实例对象状态有关

所有状态都变成 resolved,最终的状态才会变成 resolved
只要有一个变成 rejected,最终的状态就变成 rejected
 const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');

        // return 'p1';
        return Promise.reject('reason');
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');

        return 'p2';
        // return Promise.reject('reason');
      });

const p = Promise.all([p1, p2]);
      p.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

Promise.race() Promise.race() 的状态取决于第一个完成的 Promise 实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败

 const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
  const racePromise = Promise.race([p1, p2]);
      racePromise.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

Promise.allSettled() 的状态与传入的Promise 状态无关,永远都是成功的,它只会忠实的记录下各个 Promise 的表现。

 const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
 const allSettledPromise = Promise.allSettled([p1, p2]);
      allSettledPromise.then(data => {
        console.log('succ', data);
      });

3、Promise的实例方法

then方法
pending->fulfilled 时,执行 then 的第一个回调函数
pending->rejected 时,执行 then 的第二个回调函数
then 方法执行后默认是返回一个新的成功状态的Promise对象

 const p = new Promise((resolve, reject) => {
      reject();
    });
    p.then(
      () => {
        // console.log('success');
      },
      () => {
        console.log('err');
        // 在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下
        return 123;
        // 等价于
        // return new Promise(resolve => {
        //   resolve(123);
        // });
      }
    )
      .then(
        data => {
          console.log('success2', data);
          return new Promise(resolve => {
            resolve(undefined);
          });
        },
        err => {
          console.log('err2', err);
        }
      )
      .then(
        data => {
          console.log('success3', data);
        },
        err => {
          console.log('err3', err);
        }
      );

catch方法,专门用来处理 rejected 状态,本质上是 then 的特例
catch() 可以捕获它前面的错误
一般总是建议,Promise 对象后面要跟 catch 方法,这样可以处理 Promise 内部发生的错误

new Promise((resolve, reject) => {
      reject('reason');
    })
      .then(data => {
        console.log(data);
      })
      .catch(err => {
        console.log(err);
        throw new Error('reason');
      })
      .then(data => {
        console.log(data);
      })
      .catch(err => {
        console.log(err);
      });

finally,本质上是 then() 的特例。
当 Promise 状态发生变化时,不论如何变化都会执行,不变化不执行

 new Promise((resolve, reject) => {
    // resolve(123);
    reject('reason');
     })
     .finally(data => {
  console.log(data);
   })
  .catch(err => {});

4、Promise的注意事项和应用

resolve 或 reject 函数执行后的代码
推荐在调用 resolve 或 reject 函数的时候加上 return,不再执行它们后面的代码
Promise.all/race/allSettled 的参数问题
参数如果不是 Promise 数组,会将不是 Promise 的数组元素转变成 Promise 对象
Promise.all/race/allSettled 的错误处理
错误既可以单独处理,也可以统一处理,一旦被处理,就不会在其他地方再处理一遍
异步加载图片

// 异步加载图片
      const loadImgAsync = url => {
        return new Promise((resolve, reject) => {
          const img = new Image();

          img.onload = () => {
            resolve(img);
          };

          img.onerror = () => {
            reject(new Error(`Could not load image at ${url}`));
          };

          img.src = url;
        });
      };

      const imgDOM = document.getElementById('img');
      loadImgAsync('https://2img.mukewang.com/5f057a6a0001f4f918720764.jpg')
        .then(img => {
          console.log(img.src);
          setTimeout(() => {
            imgDOM.src = img.src;
          }, 1000);
        })
        .catch(err => {
          console.log(err);
        });
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343