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
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成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的执行结果 复制代码
说明:上面代码中,p1
会resolved
,p2
首先会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