目录
promise.then返回的新的promise的结果状态由什么决定?
特点
- 对象的状态不受外界影响。只有异步操作的结果可以改变这个状态,任何其他操作都不可以改变这个状态。
- 一旦状态改变,就不会在变,任何时候都可以得到这个结果。Promise 状态的改变只有两种情况:从pedding变为fulfilled或者从pending变为rejected。只要这两种情况发生了,状态就凝固了,就不会在发生改变,会一直保持这个结果,这时就被称为resolved(已定型)。如果改变已经发生,再对 Promise 对象添加回调函数,也会立即运行这个结果。这与事件(Event)不同,事件是如果错过就不会被监听到。
缺点
作用
promise可以解决异步的问题,本身不能说 promise 是异步的。
Promise.prototype.then()
Promise 实例具有 then 方法,也就是说 then 方法是定义在原型对象 Promise.prototype 上的。它的作用是为 Promise 的实例添加回调函数。then 方法的第一个参数是 resolved 状态的回调函数,第二个参数(可选)是 rejected 状态的回调函数。
then 方法返回的是一个新的 promise 实例(不是原来那个 promise 实例)。
new Promise(function (resolve, reject) {
resolve();
}).then(function () {
return 66;
}).then(function (param) {
console.log(param);
});
// 66
第一个回调函数完成以后,会将返回结果作为参数,传入到第二个回调函数。
promise.then返回的新的promise的结果状态由什么决定?
then() 回调返回的新 promise 实例状态规则,适用于其他会返回新 promise 实例的方法。
new Promise((resolve, reject) => {
resolve(1)
}).then(
value => {
console.log("onResolve1()", value);
throw 5;
// 上面输出: onResolve1() 1 onRject2() 5 onResolve3() 666
// return 2;
// 上面输出: onResolve1() 1 onResolve2() 2 onResolve3() undefined
// return Promise.resolve(333);
// 上面输出: onResolve1() 1 onResolve2() 333 onResolve3() undefined
// return Promise.reject(444);
// 上面输出: onResolve1() 1 onRject2() 444 onResolve3() 666
},
reason => console.log("onRject1()", reason)
).then(
value => console.log("onResolve2()", value),
reason => {
console.log("onRject2()", reason)
return Promise.resolve(666);
}
).then(
value => console.log("onResolve3()", value),
reason => console.log("onReject3()", reason)
)
Promise.prototype.catch()
Promise.prototype.catch 方法是 .then(null, rejection) 的别名,用于指定发生错误时的回调函数(或者说 promise 实例处于 rejected 状态时触发的函数)。
var p = new Promise(function (r1, r2) {
r2();
});
p.then(function () {
}, function () {
console.log(1);
}).catch(function () {
console.log(2);
});
p.then(function () {
}).catch(function () {
console.log(2);
});
// 1
// 2
另外,then() 方法指定的回调函数,如果运行中抛出错误,也会被 catch() 捕获。
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
如果 promise 状态已经变为 resolved ,在抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
因为 promise 状态一旦被改变就永久保持,无法再被改变了。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直至被捕获。
var p = new Promise(function (r1, r2) {
r2();
});
p.then(function () {
}).then(function () {
}).then(function () {
}).then(function () {
}).catch(function () {
console.log(2);
});
// 2
一般来说,不要在 then() 里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用 catch() 方法。因为 catch() 不仅可以执行 promise 处于 rejected 状态时方法,还可以捕获 then 方法中执行的错误。
promise 内部的错误代码不会影响到 promise 外部的代码,即使 promise 内部代码有错误,外部代码还是会正常进行,通俗的说法就是“Promise 会吃掉错误”。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为 x 没有声明
resolve(x + 2);
});
};
someAsyncThing().then(function() {
console.log('everything is great');
});
setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123
catch() 方法返回的还是一个 Promise 对象,因此后面还可以接着调用 then() 方法。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on
如果 then() 里面的方法没有报错,则会跳过 catch 方法继续往后执行。
Promise.resolve()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// carry on
Promise.prototype.finally()
finally() 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。此方法的回调函数不接受任何参数,这就意味着没办法知道前面的 Promise 的状态到底是 fulfilled 还是 rejected。这表明,finally 方法里面的操作和状态无关,不依赖于 Promise 的执行结果。
finally 本质上是 then 方法的特例。
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
底层实现
Promise.prototype.finally = function (callback) {
// this -> Promise 实例
let P = this.constructor;
// this 本身是没有 constructor 的,但是 this.__proto__.constructor 有
// this.__proto__.constructor == Promise(构造函数)
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
Promise.resolve(2).finally(() => {
// do something
}).then(p => console.log(p));
// 2
finally 在前面 promise 状态改变之后,执行回调,并将前面 promise 的返回值返回。(finally 是在前面 promise 的 then 回调里面执行)
Promise.all()
Promise.all() 方法用于将多个 promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
Promise.all() 方法接收一个数组作为参数,p1、p2、p3 都是 Promise 实例,如果不是则会调用 Promise.resolve() 将参数转为 Promise 实例,再进一步处理。
p 的状态由 p1、p2、p3 共同决定,分为两种情况:
- 只有 p1、p2、p3 的状态都变为 fulfilled ,p 的状态才会变成 fulfilled 。此时 p1、p2、p3 的返回值组成一个数组传给 p 的回调函数。
- 只要 p1、p2、p3 中只要有一个被 rejected ,p 的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数。
const p1 = new Promise(function (r1, r2) {
r1('p1 response');
});
const p2 = new Promise(function (r1, r2) {
r1('p2 response');
});
const p3 = new Promise(function (r1, r2) {
r1('p3 response');
});
Promise.all([p1, p2, p3]).then(function (posts) {
console.log(posts);
}).catch(function (reason) {
// ...
});
["p1 response", "p2 response", "p3 response"]
const p1 = new Promise(function (r1, r2) {
setTimeout(() => {
r2('p1')
}, 2000);
});
const p2 = new Promise(function (r1, r2) {
setTimeout(() => {
r2('p2')
}, 1000);
});
const p3 = new Promise(function (r1, r2) {
setTimeout(() => {
r2('p3')
}, 3000);
});
Promise.all([p1, p2, p3]).then(function (posts) {
console.log(posts);
}).catch(function (reason) {
console.log(reason);
});
// p2
如果作为参数的 promise 实例,自己定义了 catch 方法,那么一旦它被 rejected ,并不会触发 all() 的 catch 方法。
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: 报错了]
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);
Promise.all([p1, p2])
.then(result => {
console.log(result)
})
.catch(e => console.log(e));
// Error: 报错了
代码解读:p1 会 resolved ,p2 首先会 rejected ,但是 p2 有自己的 catch 方法,该方法返回的是一个 promise 实例(此实例状态:p2 的 catch 回调方法没有返回值,或者说是一个 undefined,那么 catch 方法返回新的 promise 实例的状态就是 resolved)。这样一来, Promise.all() 方法参数里面的两个实例都会 resolved,因此调用 all 的 then 方法指定的回调函数,而不会进入 catch 方法。
如果 p2 没有自己的 catch 方法,那么就会进入 all 的 catch 方法。
Promise.allSettled()
Promise.allSettled() 方法接收一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等所有这些实例都返回结果,不管状态是 resolved 还是 rejected,包装实例才会结果。
和 all() 的区别,allSettled() 可以确定每个 Promise 实例都已结束,all() 只有在一种情况下可以确定每个 Promise 实例都已结束,就是传入的 Promise 实例都变为 resolved 状态时,才能确定传入的实例都已结束,但是有一个抛出异常时,就无法确定其他的 Promise 实例是否已结束。
该方法返回的新的 Promise 实例,一旦结束,状态总是 fulfilled,不会变成 rejected。状态办成 fulfilled 后,Promise 的监听函数接收的参数是一个数组,每个数组成员对应传入 Promise.allSettled() 的 Promise 实例。
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
代码解读:Promise.allSettled() 的返回值 allSettledPromise ,状态只能变成 fulfilled 。它的监听函数接收到的参数数组是数组 results。该数组的每个成员都是一个对象,对应传入的两个 Promise 实例。每个对象都有 status 属性,属性值只能是 fulfilled 或 rejected。fulfilled 时对象有 value 属性,rejected 时对象有 reason 属性。
Promise.race()
Promise.race() 同样是将多个 Promise 实例,包装成一个新的 Promise 实例返回。
const p = Promise.race([p1, p2, p3]);
与 all() 不同的是,只要 p1、p2、p3 有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
Promise.any()
该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。只要参数有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数都变成 rejected 状态,包装实例就会变成 rejected 状态。
Promise.any() 和 Promise.race() 很像,只有一点不同,就是 Promise.any() 不会因为某一个实例变为 rejected 状态而结束。
Promise.any() 抛出的错误,是一个 AggregateError 实例。(ES6 对应的示例和文档里面不一样...)
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);
Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
console.log(result); // 42
});
Promise.any([rejected, alsoRejected]).catch(function (results) {
console.log(results); // [-1, Infinity]
});
// 第一个打印结果无异议,但是第二个打印结果...
// 反正我打印出来的是 AggregateError: All promises were rejected
Promise.resolve()
将现有对象转为一个 Promise 对象,状态为 resolved 。等价于:
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
注意这里只是等价于,并不是“全等”
参数的四种情况:
1)如果参数是 Promise 实例,那么 Promise.resolve 将不做任何修改,原封不动的返回这个实例。
var p = new Promise(function (a, b) {
a(1);
});
Promise.resolve(p).then(function (a) {
console.log(a);
});
// 1
2)参数是一个 thenable 对象。
thenable 对象指的是具有 then 方法的对象:
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
Promise.then() 方法会将这个对象转为 Promise 对象,然后立即执行 thenable 对象的 then 方法。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function (value) {
console.log(value); // 42
});
3)参数不是具有 thenable 对象,或根本就不是对象。
Promise.then() 会直接返回一个新的 Promise 对象,状态为 resolved。
4)不带任何参数。
直接返回一个 resolved 状态的 Promise 对象。
立即 resolved 的 Promise 对象,是在本轮“事件循环”的结束时执行。
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
Promise.resolved() 是一个微任务。
Promise.reject()
将现有对象转为一个 Promise 对象,状态为 rejected。
Promise.try()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。