- 可以避免多层异步调用嵌套问题
- Promise 对象提供了简介的API , 值得控制异步操作更容易
- 异步问题同步化解决方案。
- MDN
- ruanyifeng
目录
关于Promise
表了一个异步操作的最终完成或者失败。
一个 Promise
必然处于以下几种状态之一:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
Promise的特点:
- 对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。其状态改变只有两种可能pending->fulfilled/rejected。改变之后状态就凝固了,会一直保持这个结果。
Promise的缺点:
- 无法取消Promise。一旦新建就会立即执行,无法中途取消。
- 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 当处于
pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
基本用法
- 实例化promise对象,构造函数中传递函数,该函数用于处理异步任务
- resolve 和 reject 两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果
//创造promise实例
var p = new Promise(function(resolve, reject) {
// 成功时候调用 resolve()
// 将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)
// 在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
// 失败时候调用 reject()
// 将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),
// 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
// if ( 异步操作成功) {
// resolve()
// } else {
// reject()
// }
});
//Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
p.then(function(ret) {
// 从resolve得到正常的结果
}, function(ret) {
// 从reject得到错误信息
})
- Promise 新建后就会立即执行。
then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行
var p1 = new Promise(function(resolve, reject) {
console.log('is newPromise');
resolve()
})
p1.then(function(ret) {
console.log('isOK');
})
console.log('同步任务');
//is newPromise
//同步任务
//isOK
Promise.prototype.then()
它的作用是为 Promise 实例添加状态改变时的回调函数。
then
方法的第一个参数是resolved
状态的回调函数,第二个参数是rejected
状态的回调函数,它们都是可选的。
then
方法返回的是一个新的Promise
实例。因此可以采用链式写法。
//用箭头函数更清晰点
var p1 = new Promise((resolve, reject) => {
console.log('is newPromise');
resolve('123');
})
p1.then(
ret => {
console.log(ret);
return 'next';
},
error => {
console.log(error);
return 'error';
}
).then(
ret => {
console.log(ret);
},
error => {
console.log(error);
}
)
Promise.prototype.catch()
处理一个拒绝的情况。
它的行为与调用Promise.prototype.then(undefined, onRejected)
相同。
- 一般来说,不要在
then()
方法里面定义 Reject 状态的回调函数(即then
的第二个参数),总是使用catch
方法。
var p2 = new Promise((resolve, reject) => {
console.log('is newPromise');
reject();
})
p2.then(
() => console.log('catch 前的成功 then'),
// () => console.log('catch 前的拒绝 then'), 如果这个存在,就会跳过下面的catch
).catch(
() => console.log('catch error')
).then(
() => console.log('catch 后的成功 then'),
() => console.log('catch 后的拒绝 then')
)
//is newPromise
//catch error
//catch 后的成功 then
- Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个
catch
语句捕获。 - Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。
var p3 = new Promise((resolve, reject) => {
console.log('is newPromise');
resolve();
})
p3.then(
() => sum = x + 1, //x未定义 浏览器无提示
).then(
() => sum = a + 1, //a未定义
).catch(
() => console.log('catch')
)
//is newPromise
//catch
- 一般总是建议,Promise 对象后面要跟
catch()
方法,这样可以处理 Promise 内部发生的错误。
var p3 = new Promise((resolve, reject) => {
console.log('is newPromise');
resolve();
})
p3.then(
() => sum = x + 1,
).then(
() => sum = a + 1,
).catch(
(error) => {
console.log(error); //ReferenceError: x is not defined
//catch 中可以再次抛出错误 Uncaught (in promise) ReferenceError: y is not defined
y + 2
}
)
Promise.prototype.finally()
用于指定不管 Promise 对象最后状态如何,都会执行的操作。
finally
方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled
还是rejected
。
这表明,finally
方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
finally
方法总是会返回原来的值。
Promise.all()
用于将多个 Promise 实例,包装成一个新的 Promise 实例。
pall
的状态由可迭代对象决定,分成两种情况。
- 全部状态都变成fulfilled时,
pall
的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给pall
的回调函数。
var p1 = new Promise((resolve, reject) => {
resolve('isP1');
})
var p2 = 123213;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
})
var pall = Promise.all([p1, p2, p3]);
pall.then(
value => console.log(value)
//Array(3) [ "isP1", 123213, "foo" ]
)
-
中有一个被rejected,pall的状态就变成rejected.此时第一个被reject的实例的返回值,会传递给pall的回调函数。
var p1 = new Promise((resolve, reject) => {
resolve(x + 1);
})
var p2 = 123213;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
})
var pall = Promise.all([p1, p2, p3]);
pall.then(
value => console.log(value)
).catch(
error => console.log(error) //ReferenceError: x is not defined
)
- 注意,如果作为参数的 Promise 实例,自己定义了
catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。
var p1 = new Promise((resolve, reject) => {
resolve(x + 1);
}).catch(
error => console.log(error) //ReferenceError: x is not defined
//该实例执行完catch方法后,也会变成resolved
)
var p2 = 123213;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
})
var pall = Promise.all([p1, p2, p3]);
pall.then(
value => console.log(value) //Array(3) [ undefined, 123213, "foo" ]
).catch(
error => console.log(error)
)
Promise.race()
将多个 Promise 实例,包装成一个新的 Promise 实例。
- 只要其中有一个实例率先改变状态,
p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
var p1 = new Promise((resolve, reject) => {
resolve(3);
}).catch(
error => console.log(error)
)
var p2 = 123213;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
})
var prace = Promise.race([p1, p2, p3]);
prace.then(
value => console.log(value) // 123213
).catch(
error => console.log(error)
)
Promise.allSettled()
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。
只有等到所有这些参数实例都返回结果,不管是fulfilled
还是rejected
,包装实例才会结束。
该方法返回的新的 Promise 实例,一旦结束,状态总是fulfilled
,不会变成rejected
。
- 这可以确保所有操作都结束。并且获得到他们的结果。
var p1 = new Promise((resolve, reject) => {
resolve(x + 1);
})
var p2 = 123213;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
})
var allSettled = Promise.allSettled([p1, p2, p3]);
allSettled.then(
value => console.log(value)
)
Promise.any()
该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
Promise.resolve()
将现有对象转为 Promise 对象。
Promise.resolve('foo')
// 等价
new Promise(resolve => resolve('foo'))
- 参数是一个 Promise 实例。原封不动地返回这个实例。
- 参数是一个具有then方法的对象。立即执行obj的then
var obj_ = {
then : function (resolve, reject) {
resolve(1)
}
}
var p = Promise.resolve(obj_);
p.then(
value => console.log(value) //1
)
- 参数是不带then的对象,或者不是对象。则返回一个新的 Promise 对象,状态为
resolved
。
var p = Promise.resolve('Hello');
p.then(
value => console.log(value) //Hello
)
var obj_ = {
text : 'hello'
}
var p = Promise.resolve(obj_);
p.then(
value => console.log(value) //Object { text: "hello" }
)
- 不带参数。直接返回一个
resolved
状态的 Promise 对象。
var p = Promise.resolve();
Promise.reject(reason)
返回一个新的 Promise 实例,该实例的状态为rejected
。
Promise.try()