前言
传统针对异步操作的解决方案是事件和回调函数,造成层层嵌套回调的问题。Promise避免了这样的问题。
Promise对象代表一个异步操作,有3种状态:Pending(进行中)、ReSolved(已成功)、Rejected(已失败)。P=>F,得到Resolved(已成功)状态;P=>R,得到Rejected(已失败)状态。
Promise对象有以下两个特点:
- 1、对象的状态不受外界影响。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 2、一旦状态改变就不会再变,任何时候都可以得到这个结果。
一些缺点:
- 1、一旦建立它就立即执行,无法中途取消。
- 2、如果不设置回调函数,Promise内部抛出的错误不会反应到外部。
- 3、当处于Pending状态时,无法得知目前进展到哪一个阶段。
基本用法
var promise = new Promise((resolve, reject) => {
//some code
console.log('promise');
resolve();
});
console.log('hi');
promise.then(()=>{
console.log('then success');
}, () => {
console.log('then error');
});
//promise
//hi
//then success
resolve 函数的作用将“进行中”变成“已成功”状态。reject 函数的作用将“进行中”变成“已失败”状态。then可以接受两个函数。
Promise新建后就会立即执行,即先打印'promise'。
var p1 = new Promise(function (resolve, reject) {
reject('xxx');
});
var p2 = new Promise(function (resolve, reject) {
resolve(p1);
});
p2.then((res)=>{
console.log('then', res);
}).catch((error) => {
console.log('catch', error);
});
//catch xxx
reject函数的参数通常是Error对象的实例,表示抛出的异常。resolve函数的参数除了正常值外,还可能是另一个Promise实例。
如上例子中,p1 和 p2 都是 Promise 实例,p2 的 resolve 方法将 p1 作为参数,这时 p1 的状态就会传递给 p2,也就是 p1 的状态决定了 p2 的状态。如果 p1 的状态是 Pending,那么 p2 的回调函数就会等待 P1 状态改变。如果 p1 的状态已经是 Resolved 或者 Rejected 状态,那么 p2 的回调函数将会立即执行。
调用resolve和reject不会终结Promise的参数函数的执行
var p1 = new Promise(function (resolve, reject) {
reject('xxx'); //最好使用return reject('xxx');
console.log('promise');
});
console.log('out');
p1.then(()=>{
console.log('then');
}).catch(() => {
console.log('catch');
});
//promise
//out
//catch
resolve和reject以后,Promise的使命的完成了,后续的操作应该放到then方法中,resolve和reject后面不应该再执行其他语句。
Promise.prototype.then()
作用就是为Promise实例添加状态改变的回调函数。第一参数Resolved状态的回调,第二个参数可选Rejected状态回调,返回的是一个新的Promise实例。
如果then中的回调函数返回:
-
一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
-
没有返回值,那么then返回的Promise将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
-
抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
-
一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
-
一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
-
一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
Promise.prototype.catch()
是.then(null, rejection)的别名,指定发生错误时的回调函数。catch可以捕获Rejected状态抛出的错误,也可以捕获then中抛出的错误。
Promise的错误具有“冒泡”性质,会一直向后传递,直到被捕获。即错误总会被下一个catch语句捕获。如果没有catch,Promise对象抛出错误不会传递到外层代码,但是浏览器此时会打印错误。
var p1 = new Promise(function (resolve, reject) {
return resolve('xxx'); //
});
p1.then(()=>{
console.log('then1');
}).catch(() => {
console.log('catch');
}).then(()=>{
console.log('then2');
});
//then1
//then2
catch后面还可以跟then,如果没有报错直接跳过catch执行第二个then,如果第二个then有错误抛出,就与前面的catch没有关系了
其他方法
Promise.prototype.all(),最终状态由所有状态决定
Promise.prototype.race(),最终状态由率先改变状态实例决定
Promise.prototype.finally()
Promise.resolve()
Promise.resolve()作用就是将参数转成Promise实例,转换效果如下:
- 1、参数本身就是Promise实例
不做任何改变,返回这个实例
- 2、一个thenable对象
将具有then方法的对象转成Promise对象,然后立即执行thenable对象的then方法
var thenable = {
then(resolve, reject){
resolve(32);
}
}
var promise = Promise.resolve(thenable);
promise.then((value) => {
console.log(value);
});
//32
- 3、参数不是对象
如果参数不是对象,生成一个新的Promise对象,返回Promise实例的状态就是Resolved状态,所以回调函数会立即执行,参数会同时传给回调函数。
var promise = Promise.resolve(‘hello’);
promise.then((value) => {
console.log(value);
});
//hello
- 4、不带任何参数 直接返回状态是Resolved的Promise实例
注意;立即resolve的Promise对象是在本轮“事件循环”结束是,而不是在下一轮“事件循环”开始时。
题目
const p = Promise.resolve();
const ppp = new Promise((resolve, reject) => {
const pp = new Promise(resolve => {
resolve('xxx'); //修改此句resolve(p);
});
pp.then(() => {
console.log('pp1');
}).then(() => {
console.log('pp2');
});
return resolve();
});
ppp.then(()=>{
console.log('ppp1');
}).then(() => {
console.log('ppp2');
}).then(() => {
console.log('ppp3');
}).then(() => {
console.log('ppp4');
});
p.then(() => {
console.log('p1');
}).then(() => {
console.log('p2');
}).then(() => {
console.log('p3');
});
//pp1
//ppp1
//p1
//pp2
//ppp2
//p2
//ppp3
//pp3
//ppp4
/////////////
//修改后结果
//ppp1
//p1
//ppp2
//p2
//pp1
//ppp3
//p3
//pp2
//ppp4