Promise用于解决代码嵌套问题,在js中被大量使用,对于如何解决代码嵌套,可以参考文章使用Promise解决代码嵌套问题。
要做到熟悉掌握Promise,还需要弄清一些常见的问题,接下来逐一分析。
问题:什么时候会执行catch分支?
先从最简单的开始,只有一个Promise函数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| p().then(value => { console.log('111'); }, reason => { console.log(reason); }).catch(e => { console.log('crash:' + e); });
function p() { return new Promise((resolve, reject) => { throw 'hahaha' }); }
|
代码最终会输出:hahaha,也就是说走到了reject分支,catch分支并没有走到,这时我们把reject分支去掉,如下:
1 2 3 4 5
| p().then(value => { console.log('111'); }).catch(e => { console.log('crash:' + e); });
|
这种情况就会输出:crash:hahaha,走到了catch分支里,这时如果改成去掉catch分支,加上reject分支,结果会输出什么呢?其实这里还是会走到reject分支里。
那如果现在要求存在reject,又要走到catch分支,要怎么实现呢?可以在reject里继续抛出异常:
1 2 3 4 5 6 7 8
| p().then(value => { console.log('111'); }, reason => { console.log(reason); throw reason; }).catch(e => { console.log('crash:' + e); });
|
这时就会输出:
接着加大难度,在Promise代码链中抛异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function a() { console.log('执行a'); return new Promise((resolve, reject) => { throw 'hahaha'; }); }
function b() { console.log('执行b'); return new Promise((resolve, reject) => { resolve(); }); }
function c() { console.log('执行c'); return new Promise((resolve, reject) => { resolve(); }); }
a().then(value => { return b(); }).then(value => { return c(); }).then(value => { console.log('最终结果成功'); }, reason => { console.log('最终结果失败'); });
|
函数a抛异常了,因为后面两个then都没有reject,因此直接进入第三个then的reject,最终打印结果:
假如把第三个then的reject去掉,后面再加上catch,如下:
1 2 3 4 5 6 7 8 9
| a().then(value => { return b(); }).then(value => { return c(); }).then(value => { console.log('最终结果成功'); }).catch(e => { console.log('crash:' + e); });
|
意料之中,执行到了catch分支中,打印结果:
再加大难度,catch放到Promise链的中间,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| function a() { console.log('执行a'); return new Promise((resolve, reject) => { resolve(); }); }
function b() { console.log('执行b'); return new Promise((resolve, reject) => { resolve(); }); }
function c() { console.log('执行c'); return new Promise((resolve, reject) => { resolve(); }); }
function d() { console.log('执行d'); return new Promise((resolve, reject) => { resolve(); }); }
a().then(value => { return b(); }).then(value => { return c(); }).catch(e => { console.log('crash:' + e); }).then(value => { return d(); }).then(value => { console.log('最终结果成功'); }, reason => { console.log('最终结果失败'); });
|
针对上面的代码:
- 当a()执行成功,回调resolve时,catch分支不会被执行。
- 当a()执行失败,回调reject时,catch分支被执行,后面又从resolve开始执行。
- 当a()执行抛出异常时,catch分支被执行,后面又从resolve开始执行。
总结:在Promise链中,当发生了reject或者carsh,会往后查找第一个reject或者catch分支,有就执行,然后接着恢复到resolve状态,继续往下执行,如果没有找到,就crash报错。
问题:Promise.all的作用和用法?
Promise提供了all函数,用于同时执行多个Promise任务,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function a() { return new Promise((resolve, reject) => { console.log('a执行中...'); resolve('a成功'); }); }
function b() { return new Promise((resolve, reject) => { console.log('b执行中...'); resolve('b成功'); }); }
function c() { console.log('执行c'); return new Promise((resolve, reject) => { console.log('c执行中...'); resolve('c成功'); }); }
Promise.all([a(), b(), c()]).then(values => { console.log(values); }, reason => { console.log(reason); });
|
a函数,b函数和c函数都会被同时触发执行,如果有一个函数reject了,就马上回调到then的reject中,参数reason就是第一个reject传过来的,注意这时其它函数还会继续执行,而如果三个最终都resolve了,这时就会回调到then的resolve中,values就是参数数组。
问题:Promise.race的作用和用法?
与Promise.all类似,区别就是对于Promise.race,只要有一个Promise任务resolve了,就马上回调到then的resolve中,注意这时其它的Promise任务还是会继续执行的,而它们最后是resolve还是reject都会被忽略了。
很明显,对于Promise.race,then的resolve参数只有一个value,而不是values。