接触 Promise 很久了,但一直也没用过,感觉很陌生,但是ES2015来了,是时候使用了,本文将介绍Promise的方方面面,同时也是自己学习的过程。
本文将会尽可能使用ES2015的语法,这可能需要你使用一款现代浏览器,如果你还不了解可以阅读下这篇文章。
Promise的浏览器兼容性如下,你需要选一款兼容的浏览器才可以,你也可以 点击这里查看 。
Promise其实是Node社区中诞生的产物,如果你写过Node你肯定会知道为了异步,写了那么多的回调,而Promise就是比回调更有好的方式。
所谓Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进一步处理。
如果你有兴趣可以阅读一下 Promise的规范 ,但我不太感兴趣,我将从实践的角度来学习它。
Promise是一个构造函数(类),可以使用new运算符新建一个实例,然后就可以使用了,构造函数接受一个函数作为参数。
var p = new Promise((resolve, reject) => { window.setTimeout(() => {resolve(123);}, 1000); }); p.then((data) => { console.log('p success', data); });
上面的代码输出如下:
=> p success 123
新建Promise对象时传入的函数,接受两个参数,resolve和reject,分别用来改变Promise的状态,创建好,调用resolve和reject时,可以传入参数,这个参数会自动传递个后面的回调函数中。
创建好promise后,可以通过then方法定制状态变化后的回调函数。
好了这就是使用Promise的全部代码了,剩下的部分就全靠你的发挥了,下面将会介绍常用的API。
打开浏览器的控制台,输入如下代码:
Object.getOwnPropertyNames(Promise.prototype).sort().forEach(function (val) {console.log(val, '/n')});
在我的浏览器中上面的代码会有如下输出,可能不同浏览器会不一样。
这里我们将重点关注如下接口:
catch() 方法只处理Promise被拒绝的情况,并返回一个Promise。该方法的行为和调用Promise.prototype.then(undefined, onRejected)相同。
p.catch((reason) => { // 拒绝 });
更多信息, 请点击这里查看 。
then()方法返回一个Promise。它有两个参数,分别为Promise在 success 和 failure 情况下的回调函数。
p.then((value) => { // 满足 }, (reason) => { // 拒绝 });
更多信息, 请点击这里查看 。
我们也先来看看浏览器支持哪些接口,在控制台输入如下代码:
Object.getOwnPropertyNames(Promise).sort().forEach(function (val) {console.log(val, '/n')});
会看到如下的输出:
我们将重点关注一下属性:
Promise.all(iterable) 方法返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决。
Promise.all(iterable);
iterable是一个可迭代对象,比如Array。
更多信息, 请点击这里查看 。
Promise.race(iterable)方法返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后,立刻以相同的解决值被解决或以相同的拒绝原因被拒绝。
Promise.race(iterable);
iterable是一个可迭代对象,比如Array。
更多信息, 请点击这里查看 。
Promise.reject(reason)方法返回一个用reason拒绝的Promise。
Promise.reject(reason);
reason Promise被拒绝的原因。
更多信息, 请点击这里查看 。
Promise.resolve(value)方法返回一个以给定值resolve掉的Promise对象。但如果这个值是thenable的(就是说带有then方法),返回的promise会“追随”这个thenable的对象,接收它的最终状态(指resolved/rejected/pendding/settled);否则这个被返回的promise对象会以这个值被fulfilled。
Promise.resolve(value); Promise.resolve(promise); Promise.resolve(thenable);
value 用来resolve待返回的promise对象的参数。既可以是一个Promise对象也可以是一个thenable。
更多信息, 请点击这里查看 。
我们构造一段下面的代码,基本上用到了上面的全部知识:
// 1000ms 后success var p1 = new Promise((resolve, reject) => { window.setTimeout(() => {resolve(123);}, 1000); }); p1.then((data) => { console.log('p1 success', data); }); // 2000ms 后success var p2 = new Promise((resolve, reject) => { window.setTimeout(() => {resolve(456);}, 2000); }); p2.then((data) => { console.log('p2 success', data); }); var pa = Promise.all([p1, p2]); var pr = Promise.race([p1, p2]); pa.then((data) => { console.log('pa success', data); }); pr.then((data) => { console.log('pr success', data); });
上面的代码输出如下:
// 1000ms p1 success 123 pr success 123 // 2000ms p2 success 456 pa success [123, 456]
如果要兼容旧的浏览器,又要使用新特性,那么只能使用Polyfill了,类似的库很多,我推荐使用 es6-promise
es6-promise是一个兼容 ES6 Promises 的Polyfill类库。 它基于 RSVP.js 这个兼容 Promises/A+ 的类库, 它只是 RSVP.js 的一个子集,只实现了Promises 规定的 API。
关于使用方法和注意事项这个库的文档都写得很详细了,在此不再详细介绍了。
是时候使用Promise了,上面已经介绍了ES2015 Promise的全部内容了,如果你还想阅读更多资料,可查看下面的参考资料,如果你有任何疑问或建议,欢迎在下面的评论区和我讨论。