Promise简单学习
本文由 小茗同学 发表于 2016-10-09 浏览(2549)
最后修改 2018-06-18 标签:javascript es6 promise

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

resolvereject可以大致理解为成功回调和失败回调,看下面例子:

还是借用上面的例子:

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 种状态中的一种:pendingresolvedrejected。状态转变只能是 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