Promise用法介绍
ES6
中内置了Promise
,非ES6下也有很多第三方实现。Promise
是JS中异步编程的一种解决方案,主要是为了解决异步回调深渊。
我喜欢偷懒,懒得介绍杂七杂八等等,直接上代码。
最基本用法
先来看个例子:
// 用setTimeout模拟简单的ajax,num传参来人为模拟成功或者失败,大于10表示成功
function ajax(num) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if(num >= 10) resolve('成功:' + num);
else reject('失败:' + num);
}, 1000);
});
}
ajax(12) // 先来一次成功
.then(function(data) {
console.log(data);
return ajax(16); // 可以再次返回一个Promise实例,
})
.then(function(data) {
console.log(data);
return '我是直接返回的结果'; // 也可以直接返回结果
})
.then(function(data) {
console.log(data);
return ajax(5); // 模拟一次失败
})
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.warn(error); // catch会捕获前面所有可能的错误
});
执行结果如下(可以看到,12和16之间间隔了1秒,而16和直接返回的结果之间几乎没有间隔):
reject
resolve
和reject
可以大致理解为成功回调和失败回调,看下面例子:
还是借用上面的例子:
function ajax(num) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if(num >= 10) resolve('成功:' + num);
else reject('失败:' + num);
}, 1000);
});
}
ajax(4)
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.warn(error)
});
还可以这么写,then里面传2个函数,第一个是成功回调,第二个是失败回调:
ajax(4)
.then(function(data) {
console.log(data);
}, function(error) {
console.warn(error)
});
这2种写法在这里基本上差不多,但是一般都推荐第一种写法,因为如果then的成功回调里面也报错了,第一种写法并不会停下来阻止后面代码的运行。
catch
Promise链中的错误会被最近的一个catch
捕获,如果没有定义catch方法,则抛出异常:
ajax(12)
.then(function(data) {
console.log(data);
a[0] = 10; // 人为制造错误
})
.catch(function(error) {
console.warn(1, error); // 这里会抛出错误:a is not defined
return ajax(2);
})
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.warn(2, error)
});
三种状态
Promise
本质是一个状态机。每个Promise
对象只能是 3 种状态中的一种:pending
、resolved
或 rejected
。状态转变只能是 pending
-> resolved
或者 pending
-> rejected
,且状态转变不可逆。
我们还是看例子:
var p1 = ajax(12);
console.log('p1:', p1);
p1.then(function(data) {
console.log('p1:', p1);
});
var p2 = ajax(5);
console.log('p2:', p2);
p2.then(function(data) {
console.log('p2:', p2);
})
.catch(function(error) {
console.log('p2:', p2);
});
运行结果:
PS:不知为何,阮一峰的promise介绍里把resolved
状态说成fulfilled
了,经测试,并没有这种状态。
立即执行
特别注意,new
完一个Promise
对象之后,回调函数会立即执行!
静态方法
Promise.all
Promise.all
方法提供了并行执行异步操作的能力,它等到所有异步方法全部执行完毕了再执行then方法,并将所有异步方法的返回结果放到一个数组里面作为参数。
Promise
.all([ajax(12), ajax(14)])
.then(function(results)
{
console.log(results); // 输出:["成功:12", "成功:14"]
});
Promise.race
Promise.all
方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这个方法就是Promise.race
。
我们把task1的延时改为1秒钟再试:
function ajax1(num) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if(num >= 10) resolve('成功:' + num);
else reject('失败:' + num);
}, 1000);
});
}
function ajax2(num) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if(num >= 10) resolve('成功:' + num);
else reject('失败:' + num);
}, 2000);
});
}
Promise
.race([ajax1(12), ajax2(14)])
.then(function(results)
{
console.log(results); // 输出:成功:12
});
本文有待完善
参考
http://es6.ruanyifeng.com/#docs/promise
https://zhuanlan.zhihu.com/p/25178630
http://www.cnblogs.com/lvdabao/p/es6-promise-1.html