阅读 283

ES6中的promise,带你真正弄懂promise的各种方法的用法

1.含义

promise 是异步编程的一种解决方案,promise对象是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从他获取异步操作的消息。

1)promise 对象的特点:

  • 对象的状态不受外界的影响。promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功) 和 rejected(已失败);

  • 一旦状态改变,就不会再改变,任何时候都可以得到这个结果;

2)缺点:

  • 无法取消promise,一旦新建他就会立即执行,无法中途取消

  • 如果不设置回调函数,promise内部抛出的错误,不会反应到外部

  • 当处于pending状态时,无法得知目前的状态是刚刚开始还是即将完成

2.基本用法

promise对象是一个构造函数,用来生成promise实例。

const promise = new Promise(function(resolve, reject) {   // ... some code   if (/* 异步操作成功 */){     resolve(value);   } else {     reject(error);   } }); // 理解:promise构造函数接受俩个参数,分别是resolve 和reject。 复制代码

promise.then(function(value) {   // success }, function(error) {   // failure }); // promise 实例生成后,可以使用then 方法 分别指定 resolved状态 和reject 状态的回调函数。 复制代码

1)promise 新建后就会立即执行

let promise = new Promise(function (resolve,reject) {         console.log("1,promise");         resolve();     })     promise.then(function () {         console.log('3,resolved.')     })     console.log("2,hello")  //  promise 新建之后立即就会执行---所以就会立即执行 输出 1,promise  //  then  方法指定的回调函数,将在当前脚本所有任务同步执行完成之后才会执行----输出 在 2 hello 之前按照顺序执行 和 1,hello  //  当当前脚本执行完毕之后,then里的内容才会执行 ----  输出 3,resolved 复制代码

2) 调用 resolve或者reject 并不会终结 promise 的参数函数的执行。

new Promise((resolve, reject) => {   resolve(1);    return  resolve(1);  // 加上这行话 就不会在输出2   console.log(2); }).then(r => {   console.log(r); }); // 因为立即 resolved 的Promise 是在本轮事件循环的末尾执行,总是晚于本轮事件循环的同步任务。所以先输出2后输出1的内容 更好的写法: new Promise((resolve, reject) => {    return  resolve(1);   }).then(r => {   console.log(2);   console.log(r); }); 输出的结果 //2 //1 复制代码

3. Promise.prototype.then()

then方法是定义在原型对象Promise.prototype上的,为Promise 实例添加状态改变时的回调函数。 then方法返回一个新的promise实例,注意不是原来的Promise实例

getJSON("/post/1.json").then(function(post) {   return getJSON(post.commentURL); }).then(function (comments) {   console.log("resolved: ", comments); }, function (err){   console.log("rejected: ", err); }); // 等价写成箭头函数的写法 getJSON("/post/1.json").then(   post => getJSON(post.commentURL) ).then(   comments => console.log("resolved: ", comments),   err => console.log("rejected: ", err) ); 复制代码

4.Promise.prototype.catch()

1、含义

Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

catch 捕获promise 抛出的异常的状态rejected或者是then 方法指定的回调函数在运行中抛出的错误,也会被catch方法捕获。

const promise = new Promise(function(resolve, reject) {   throw new Error('test'); }); promise.catch(function(error) {   console.log(error); }); // Error: test // 写法一 const promise = new Promise(function(resolve, reject) {   try {     throw new Error('test');   } catch(e) {     reject(e);   } }); promise.catch(function(error) {   console.log(error); }); // 写法二 const promise = new Promise(function(resolve, reject) {   reject(new Error('test')); }); promise.catch(function(error) {   console.log(error); }); 复制代码

2、catch 返回一个promise对象,同时还可以继续调用then方法

 const someAsyncThing = function () {         return new Promise(function (resolve,reject) {             // 因为 x 没有被声明定义,所以会报错            // let x = 5;  // 如果声明了,则不会报错             resolve(x +2);         })     }     //调用someAsyncThing     someAsyncThing().catch(function (error) {         console.log('no no no',error)     }).then(function () {         console.log('carry on');     }) // 因为 x 没有被声明定义,所以会报错 在运行完catch()方法指定的回调函数之后,会接着 // 运行后面的then()方法指定的回调函数。如果没有报错,则会跳过catch()方法。 复制代码

5.promise.prototype.finally()

1、含义

  • finally()方法用于指定不管promise 对象最后的状态 如何,都会执行的操作。

  • finally 方法的回调函数不接受任何参数,所以finally方法里面的操作和promise 返回的状态无关,不依赖于promise的执行结果。

2、finally 本质是then方法的特例。

promise .finally(() => {   // 语句 }); // 等同于 promise .then(   result => {     // 语句     return result;   },   error => {     // 语句     throw error;   } ); // 说明:如果不使用finally方法,同样的语句需要为成功和失败俩种情况各写一次。有了finally方法,则只需要写一次。 复制代码

6.promise.all()

1.含义

promise.all() 方法用于将多个Promise 实例,包装成一个新的实例。

const p = Promise.all([p1, p2, p3]);  复制代码

promise.all() 方法接受一个数组作为参数,p1、p2、p3 都是他的实例。如果参数不是数组的话,但必须有iterator 的接口,且返回的每一个成员都是promise 实例。

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    const p1 = new Promise((resolve, reject) => {         resolve('hello');     })         .then(result => result)         .catch(e => e);     const p2 = new Promise((resolve, reject) => {         throw new Error('报错了');     })         .then(result => result)         .catch(e => e);     Promise.all([p1, p2])         .then(result => console.log(result))         .catch(e => console.log(e));     // ["hello", Error: 报错了] ---- 这是rejected 输出的语句     // Array(2)  0:hello 1:Error: 报错了   --- 这是resolv的执行结果 复制代码

说明:上面代码中,p1resolvedp2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

7.总结

  • all() :是数组中的所有的对象变为resolve 只要有一个状态变为reject 则执行 all() 方法里的内容。

  • race():只要有一个实例发生改变时,P的总数组的状态就会随之改变。

  • allSettled():只有等待这些参数的实例都返回的结果,不管是fulfilled 还是rejected,包装实例才会结束。

  • any():只要参数所有的实例都变成fulfilled状态,包装的实例就会变成rejected 状态。如果所有的参数实例都变成rejected状态。包装实例就会变成rejected状态。

8.promise.resolve()

需要将现有的对象转为promise 对象,promise.resolve() 方法就起到这个作用。

1、参数是一个Promise 实例

如果参数是一个promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

2、参数是一个thenable 对象

thenable对象指的是具有then方法的对象。

let thenable = {   then: function(resolve, reject) {     resolve(42);   } }; let p1 = Promise.resolve(thenable); p1.then(function (value) {   console.log(value);  // 42 });  // 总结:promise.resolve()方法会将这个对象转为promise 对象,然后立即执行thenable 对象的then 方法     // thenable 对象的then()方法执行后,对象P1状态就变为resolved。从而立即执行最后那个then方法指定的回调函数      // 最后输出的结果为42 复制代码

3、参数不是具有then方法的对象,或者根本就不是对象

const p = Promise.resolve('Hello'); // 字符串对象不具有then() 方法 p.then(function (s) {   console.log(s) }); // Hello 复制代码

如果参数是一个原始值,或者是一个不具有then() 方法的对象,则Promise.resolve()方法返回一个新的Promise对象(从一生成的状态就是resolved,所以回调函数会立即执行),状态为resolved。

4、不带有任何参数

注:立即resolve()的promise 对象,是在本轮事件循环的结束时执行,而不是在下一轮的事件循环的开始时执行。

setTimeout(function () {   console.log('three'); }, 0); Promise.resolve().then(function () {   console.log('two'); }); console.log('one'); // one // two // three 复制代码

setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。


作者:striving
链接:https://juejin.cn/post/7036172322578890788

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐