JavaScript被设计为单线程(webWoker可以处理多线程),利用事件轮询机制,可以模拟出多线程效果,也就是异步操作,而回调函数callback是事件轮询调用的目标方法。
但是,通过回调函数处理异步事件有很多不确定性,并且容易陷入“回调地狱”-嵌套太深。于是,Promise概念被提出,并且很多JavaScript框架(比如JQuery)支持的异步API都基于Promise理念构建的。
1.什么是Promise?
Promise是一个对象,用来传递异步操作的信息,它代表了某个未来时刻才知道结果的事件,并且这个事件提供统一API接口。
2. Promise对象
Promise原型对象提供的主要方法有:
//添加状态改变时的回调函数
Promise.prototype.then(resolvedFunc, rejectedFunc)
//响应rejected状态的promise(如果前面有错误抛出,会产生一个rejected状态的promise)
//相当于promise.then(null, rejectedFunc)
Promise.prototype.catch(rejectedFunc)
参考一个标准的Promise实例:
var promise = new Promise(function(resolve, reject){
// 你的代码---pending状态
if (isSuccessful) {
resolve(value); // 成功
}
else {
reject(error); // 失败
}
// 这里的代码永远不会被运行
});
promise
.then(
function(value){//resolved时调用},
function(error){// rejected时调用})
.catch(function(error){//有错误抛出时调用});
promise对象有如下特点:
- 可以利用promise对象创建一个异步操作。
- 有三种状态:pending, resolved和rejected。异步代码运行时为pending,运行后的结果只会是两种:成功-resolved,或者失败-rejected。状态变化是单行流动,不可逆转。
- 在一个promise里,resolve或者reject方法只会被调用一次。
- resolve()/reject()可以利用参数传递数据,但是,只支持传递第一个参数。也就是说,promise决议只能传递单个值/对象。因此,实际应用中,需要将多个值封装在一个对象中传递。
- then()和catch()函数都会默认返回一个promise对象。
- 如果没有给then()传递函数作为完成处理函数参数,还是会有替代的默认处理函数,并且,该默认函数会把接受到的值传递给下一个promise对象。
getPromise(40, true).
then(null,null).then(function (value) {
console.log("resolved:"+value);
});
// 打印:resolved:40
// 可见,如果不设置then的处理函数参数,resolved值40一直会被传递下去。
3. 一个Promise实例
下面是一个Promise例子,参考注释。
创建promise的工厂方法:
var getPromise = function (val, isSuccessful) {
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
if (isSuccessful) {
// 决议成功,回调then()的第一个函数参数
resolve(val);
}
else {
// 决议失败,回调then()的第二个函数参数
reject(new Error("oh, error!"));
}
}, 0);
});
return promise;
};
第一次测试(连续调用两次promise):
getPromise(30, true).then((value) => {
console.log("the first resolved status: " + value);
// 返回一个promise对象,该promise决议结果会决定下一个then()函数应该调用哪个回调函数
// 如果不显性返回promise对象,ES6会默认创建一个空值promise对象最为返回值
return getPromise(20, true);
}, (error) => {
console.log("the second rejected status: " + error);
}).then((value) => {
console.log("the second resolved status: " + value);
// 一个rejected状态的promise对象被返回
//由于后续没有then(),因此catch函数捕获错误状态
throw new Error('create a error!');
}, (error) => {
console.log("the second rejected status: " + error);
}).catch((error) => {
console.log("Catch: " + error);
});
//运行结果:
the first resolved status: 30
the second resolved status: 20
Catch: Error: create a error!
第二次测试(多加一个then调用):
getPromise(30, true).then((value) => {
console.log("the first resolved status: " + value);
return getPromise(20, true);
}, (error) => {
console.log("the second rejected status: " + error);
}).then((value) => {
console.log("the second resolved status: " + value);
// 一个rejected状态的promise对象被返回
//由于后续有then(),因此then函数的第二个回调函数被运行
throw new Error('create a error!');
}, (error) => {
console.log("the second rejected status: " + error);
}).then((value) => {
console.log("the third resolved status: " + value);
}, (error) => {
console.log("the third rejected status: " + error);
}).catch((error) => {
console.log("Catch: " + error);
});
// 运行结果:
the first resolved status: 30
the second resolved status: 20
the third rejected status: Error: create the first error!
第三次测试(修改getPromise函数):
var getPromise = function (val, isSuccessful) {
var promise = new Promise(function (resolve, reject) {
if (isSuccessful) {
resolve(val);
//resolve之后抛出错误,是不会被捕获的
throw new Error('error, error, error!');
}
else {
reject(new Error("oh, error!"));
}
});
return promise;
};
// 测试1和测试2的运行结果不会改变
从上面的例子可以看到,可以用同步书写方式连续调用多个异步请求。并且,Promise还提供了静态函数帮助解决更复杂的异步编程场景。
4. Promise静态方法
Promise提供的静态方法有:
Promise.all([promise1, promise2 [,promiseN]])
Promise.race([promise1, promise2 [,promiseN])
Promise.resolve()
Promise.reject()
(1) Promise.all()
将多个promise实例包装成一个新的promise对象,只有多个promise的状态都为resolved,Promise.all()的状态才会变为resolved。
继续上面的例子,测试如下:
Promise.all([
getPromise(20, true),
getPromise(30, true),
getPromise(40, true)])
.then(function (value) {
console.log(value);
});
// 输出为:[ 20, 30, 40 ]
每个Promise实例的resolved值都会暂存在一个数组里,最后,该数组被传递到Promise.all()的resolved回调函数。
(2) Promise.race()
将多个promise实例包装成一个新的promise对象,只有第一个promise状态为resolved时,Promise.race()的状态才变为resolved。
并且,第一个promise的值会传递给Promise.race()。
基于上面例子继续测试:
Promise.race([
getPromise(20, true),
getPromise(30, false),
getPromise(40, false)])
.then(function (value) {
console.log(value);
}, function (error) {
console.log(error);
});
//输出为: 20
Promise.race([
getPromise(20, false),
getPromise(30, true),
getPromise(40, false)])
.then(function (value) {
console.log(value);
}, function (error) {
console.log(error);
});
// 输出为: [Error: oh, error!]
(3) Promise.resolve()
该方法会返回一个Promise对象,情况分为两种:
- 如果目标对象不是Promise对象,该方法会创建一个Promise对象
- 如果目标对象本身就是Promise对象,该方法会将这个Promise对象直接返回
// p2和p1行为完全一样
var p1 = new Promise(function(resolve, reject){
resolve(40);
});
var p2 = Promise.resolve(40);
// 向Promise.resolve()传递一个Promise对象,则直接返回这个对象
var p3 = Promise.resolve(p2);
console.log(p2===p3); // true
(4) Promise.reject()
返回一个新的Promise实例,状态为rejected:
var p = new Promise(function(resolve, reject){
reject("error");
});
//可以用 Promise.reject()快速创建promise对象,状态为rejected
var p = Promise.reject("error");
p.then(null, function(error) {
// 回调函数被调用
});
微信公众号:
网友评论