文章目录
Promise是异步编程的一种解决方案。避免了类似于$.ajax()这种多个异步操作层层嵌套的问题。
Promise对象的特点:
- Promise对象有三种状态:
padding(初始状态)、fulfilled(异步成功之后的状态)、rejected(异步失败的状态),改变状态的方式只有一种即异步的结果:如果成功状态由padding——>fulfilled;否则状态由padding——>rejected。无法提供其他方式改变状态。 - 状态一旦改变就无法更改。
- 无法取消Promise,一旦建立就会执行。。。
Promise语法
new Promise((resolve, reject) => {
if (异步成功后) {
resolve(value)//将Promise的状态由padding改为fulfilled
} else {
reject(error)//将Promise的状态由padding改为rejected
}
}).then(value => {
// resolve回调
}, error => {
// reject回调
})
上面的代码表示如果异步成功后就会调用.then()里面的第一个参数方法,否则就会调用.then()里面的第二个参数方法。如果调用resolve和reject有参数则会将参数分别传递给回调函数(.then里面的第一个和第二个参数方法)。
resolve的参数除了正常值外还可以是一个Promise实例。如:
let p1 = new Promise((resolve, reject) => {
// ...
})
let p2 = new Promise((resolve, reject) => {
// ...
resolve(p1)
})
上面的代码中p1、p2为Promise实例。p2的resolve将p1作为参数。即:一个异步操作的结果是返回另一个异步操作。
注意:这时p1的状态决定了p2的状态。如果p1的状态为padding那么p2的回调会等p1的状态改变后执行(即p1成功或失败);如果p1的状态为resolved或rejected那么p2的回调会立即执行。
示例:
let p1 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject(new Error('发生错误嘹'))
},3000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(p1)
},1000)
}).then(value => {
console.log(value)
}).catch(error=>{
console.log(error)
})
正因为如此上面代码p2最终执行的是catch()方法,并不会走then()方法。
调用resolve或reject并不会终结 Promise 的参数函数的执行。
代码示意:
new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('then')
console.log('promise')
},2000)
}).then(value => {
console.log(value)
})
//执行结果
//promise
//then
一般来说上面的console.log('promise')如果要执行放到回调函数更加规范
Promise.then()
.then()的作用是为 Promise 实例添加状态改变时的回调函数。
.then()方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。它的返回的是一个新的Promise实例。因此可以采用链式写法。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
)
上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB。
Promise.catch()
用于指定发生错误时的回调函数,最好是在.then()的链式调用最后调用一下此方法来捕获异常。它的返回值仍然是个Promise对象
new Promise((resolve, reject) => {
throw new Error('出现错误了')
}).then(value => {
}).catch(error=>{
console.log(error)
})
上面代码中如果Promise对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。
如果 Promise 状态已经变成resolved,再抛出错误是无效的。
new Promise((resolve, reject) => {
resolve('data')
throw new Error('出现错误了')
}).then(value => {
console.log(value)
}).catch(error=>{
console.log(error)
})
这时不会运行catch()里面的方法
一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
如果没有使用catch方法指定错误处理的回调函数,Promise 对象即便抛出错误也不会影响到其它代码
Promise.finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
finally本质上是then方法的特例。如下代码是等效的:
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
Promise.all()
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3])
p1、p2、p3都为Promise实例,如果不是调用Promise.resolve将它们转成Promise实例。p的状态由p1,p2,p3共同决定如果它们的状态全都为fulfilled则p的状态变成fulfilled,此时p1,p2,p3的返回值组成一个数组传递给p的回调- 若
p1,p2,p3中只要有一个为rejected,则p的状态变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。 - 若
p1,p2,p3自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.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: 报错了]
上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。
Promise.race()
此方法和Promise.all()一样接收多个Promise实例,返回一个新的Promise实例。
const p = Promise.race([p1, p2, p3]);
和Promise.all()的不同之处是只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
Promise.resolve()
Promise.resolve()的作用是将现有对象转换成Promise对象。
以下的写法是等效的
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
Promise.resolve()参数的4种情况
参数是一个 Promise 实例
参数是一个 Promise 实例,这种情况Promise.resolve()什么都不做
参数是一个thenable对象
参数是具有then方法的对象(thenable对象),Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。例如:
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42
参数是普通对象或原始值
参数不是具有then方法的对象,或根本就不是对象,Promise.resolve返回一个状态为resolved的对象
const p = Promise.resolve('Hello');
// 因为p的状态为resolved所以.then()会立即执行
p.then(function (s){
console.log(s)
});
// Hello
不带任何参数
这种情况直接返回状态为resolved的Promise对象。如果希望得到一个 Promise 对象,比较方便的方法就是直接调用。
立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。示例:
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’)则是立即执行,因此最先输出。
Promise.reject()
返回状态为rejected的Promise对象
以下两种写法等效
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => {
reject('出错了')
})
p.catch(error=>{
console.log(error)
})
// 出错了
本文深入解析Promise对象的概念,包括其特点、语法及各种方法的使用,如then、catch、finally、all、race、resolve和reject,帮助理解异步编程的解决方案。
2967

被折叠的 条评论
为什么被折叠?



