一:什么是promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。Promise对象是一个代理对象,一个代表未知返回结果的对象值。这个值在Promise对象创建时可能是未知的,它允许你为异步操作的成功和失败分别绑定相应的处理方法, 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是返回一个能代表未来出现的结果的promise对象,看起来很抽象,还是用实例来了解吧!
二:状态
pending:初始状态
fulfilled:成功状态
rejected:失败状态
1、fulfilled、rejected被统称为settled,fulfilled也可被称为resolved即为正确时走的状态
2、只有两种状态变化过程:pending → fulfilled,pending → rejected,且状态只可变化一次,一旦发生变化便会一直保持这个结果。
三、使用
new Promise(executor)
executor:一个带有两个参数(resolve和reject)的方法,resolve为fulfilled状态,即成功之后调用,reject为rejected状态,即失败之后调用。
即:new Promise(function(resolve, reject){})
1、executor在创建Promise对象时立即调用
2、若executor函数中抛出错误,promise状态为rejected,executor函数返回值被忽略
先 new一个Promise,示例如下:
let p = new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('执行完成Promise');
resolve('要返回的数据可以任何数据例如接口返回数据');
}, 2000);
});
刷新页面会发现过了2秒控制台直接打出:
执行完成Promise
其执行过程是:执行了一个异步操作,也就是setTimeout,2秒后,输出“执行完成”,并且调用resolve方法。在随后介绍的then方法中,可获取resolve方法所传回的值。
注意!我只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了,可放在方法中需要的时候进行调用如下所示:
onclickPromise:function(){
console.log('放在方法中被调用')
let p = new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('执行完成Promise');
resolve('要返回的数据可以任何数据例如接口返回数据');
}, 2000);
});
return p;
}
调用为:
this.onclickPromise();
四:方法
1、Promise.then(resolve[, reject])
resolve为成功回调函数,reject为失败回调函数(可选),参数为Promise实例返回值
promiseClick: function (num){
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('数值:', num)
if (num <= 10) {
resolve(num);
}
else {
reject('数字大于10了即将执行失败回调');
}
}, 2000);
})
return p
}
调用then的例子如下:
this.promiseClick(4).then(
function (data) {
console.log('resolved成功回调');
console.log('成功回调接受的值:', data);
},
function (reason, data) {
console.log('rejected失败回调');
console.log('失败执行回调抛出失败原因:', reason);
console.log('失败执行回调data是什么:', data);
}
);
当传入的值为4时,执行正确操作,调用resolve方法:
数值: 4
resolved成功回调
成功回调接受的值: 4
输入11时执行错误接口调用reject方法,输出如下:
数值: 11
rejected失败回调
失败执行回调抛出失败原因: 数字大于10了即将执行失败回调
失败执行回调data是什么: undefined
从上面的结果可知,在then方法中,放在第一位的方法表示正确时处理的方法,放在第二位的方法表示错误是调用的方法。
reject: (reason?: any)方法的参数可以是any,这样在then就是传什么输出什么。resolve: (value?: any)也一样,都是回填在then方法中的第一个参数。
promise().then().then().then()
then支持延续任务调用方式,下面所示在第一个promiseClick1(1).then中调用promiseClick2,进入第二个then然后再调用promiseClick3
var that = this
this.promiseClick1(1).then(
function(data) {
console.log('resolved成功回调');
that.promiseClick2(3)
}).then(
function (data) {
that.promiseClick3(3)
})
2、Promise.catch(reject)
处理内容包括:① rejected状态对应返回结果,② catch方法前抛出的错误
this.promiseClick(11).then(
function(data) {
console.log('resolved成功回调');
console.log('成功回调接受的值:', data);
})
.catch(function(reason, data) {
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:', reason);
});
错误的时候执行结果走catch:
数值: 11
catch到rejected失败回调
catch失败执行回调抛出失败原因: 数字大于10了即将执行失败回调
效果和写在then的第二个参数里面一样。它将大于10的情况下的失败回调的原因输出,但是,它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。如下:
this.promiseClick(4).then(
function(data) {
console.log('resolved成功回调');
console.log('成功回调接受的值:', data);
console.log(noData);
})
.catch(function(reason, data) {
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:', reason);
});
在第一个then中调用console.log(noData);方法,由于noData未定义,所以会马上执行cath方法中,输出如下
数值: 4
resolved成功回调
成功回调接受的值: 4
catch到rejected失败回调
catch失败执行回调抛出失败原因: ReferenceError: noData is not defined
3、Promise.all([p1, p2, ... , p(n)])
p(n)(n = 1, 2, ... )均为Promise实例
***注:返回Promise实例的状态为rejected,即Promise实例的状态为rejected,且没有catch方法做异常处理
Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
.then(function(results) {
console.log(results);
})
.catch(function (reason, data) {
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:', reason);
});
},
promiseClick1: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('数值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick1数字大于10了即将执行失败回调");
}
}, 2000);
})
return p
},
promiseClick2: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('数值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick2数字大于10了即将执行失败回调");
}
}, 2000);
})
return p
},
promiseClick3: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('数值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick3数字大于10了即将执行失败回调");
}
}, 2000);
})
return p
}
① 只有参数中所有Promise实例的状态都为fulfilled,该方法返回的Promise实例状态为fulfiiled,意思为所有的都是执行resolve方法,最终才会执行正确的结果,只要有一个是reject方法,最终都是错误的方法,同样会到then里的第二个function或者是catch中。
Promise.all([this.promiseClick3(4), this.promiseClick2(5), this.promiseClick1(6)])
.then(function(results) {
console.log(results);
});
输出:
数值: 4
数值: 5
数值: 6
[4, 5, 6]
② 参数中返回Promise实例的状态为rejected的数量大于等于1,该方法返回的Promise实例状态为rejected,返回数据为第一个状态变为rejected的参数方法返回结果
Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
.then(function(results) {
console.log(results);
})
.catch(function (reason, data) {
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:', reason);
});
输出:
数值: 4
数值: 12
catch到rejected失败回调
catch失败执行回调抛出失败原因: promiseClick2数字大于10了即将执行失败回调
数值: 11
4、Promise.race([p1, p2, ... , p(n)])
p(n)(n = 1, 2, ... )均为Promise实例
all是等所有的异步操作都执行完了再执行then方法,那么race方法就是相反的,谁先执行完成就先执行回调。
Promise
.race([this.promiseClick3(5), this.promiseClick2(11), this.promiseClick1(12)])
.then(function (results) {
console.log("第一个function:"+results);
}, function (reason) {
console.log("第二个function:" +reason);
});
输出:
数值: 5
第一个function:5
数值: 11
数值: 12
调用:
Promise
.race([this.promiseClick3(11), this.promiseClick2(5), this.promiseClick1(12)])
.then(function (results) {
console.log("第一个function:"+results);
}, function (reason) {
console.log("第二个function:" +reason);
});
输出:
数值: 11
第二个function:promiseClick3数字大于10了即将执行失败回调
数值: 5
数值: 12
从以上例子可以看出,只会进入一个then的方法,而且是根据第一个执行的状态进行判断。
5:Promise.finally( )
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
this.promiseClick1(1).then(
function(data) {
console.log('resolved成功回调');
console.log('成功回调接受的值:', nodata);
}).catch(
function(data) {
console.log('catch:' + data);
}).finally(
function(data) {
console.log('不管过程是咋样的,最终都会走到finally方法中');
})
结果:
数值: 1
resolved成功回调
catch:ReferenceError: nodata is not defined
不管过程是咋样的,最终都会走到finally方法中
6:promise.done( )
Promise 对象的回调链,不管以then
方法或catch
方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。因此,我们可以提供一个done
方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。