关于Promise
Promise
实例一旦被创建就会被执行
Promise
过程分为两个分支:pending=>resolved
和pending=>rejected
Promise
状态改变后,依然会执行之后的代码:
1 2 3 4 5 6 7 8 9 const warnDemo = ctx => { const promise = new Promise (resolve => { resolve(ctx); console .log("After resolved, but Run" ); }); return promise; }; warnDemo("ctx" ).then(ctx => console .log(`This is ${ctx} ` ));
then
方法在Console
键入以下内容:
1 2 let t = new Promise (() => {});t.__proto__;
可以看到,then
方法是定义在原型对象Promise.prototype
上的。
then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。
写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function func (args ) { return new Promise ((resolve,reject )=> { if (... ) { resolve(...) } else { let err = new Error (...) reject(err) } }) } func(ARGS).then(()=> { },()=> { })
连续调用then
因为then
方法返回另一个Promise
对象。当这个对象状态发生改变,就会分别调用resolve
和reject
写法如下:
1 2 3 4 5 6 func(ARGS).then(()=> { ... }).then( ()=>{ ... }, () => { ... } )
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function helloWorld (ready ) { return new Promise ((resolve, reject ) => { if (ready) { resolve("Right" ); } else { let error = new Error ("arg is false" ); reject(error); } }); } helloWorld(false ).then( msg => { console .log(msg); }, error => { console .log(error.message); } );
catch
方法等同于 .then(null, rejection)
。另外,then
方法指定的回调函数运行中的错误,也会被catch
捕获。
所以,之前的写法可以改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function func (args ) { const promise = new Promise ((resolve,reject )=> { if (... ) { resolve(...) } else { let err = new Error (...) reject(err) } }) return promise } func(ARGS).then(()=> { }).catch(()=> { }).then(()=> { })...
finally
方法
指定不管 Promise
对象最后状态如何,都会执行的操作。可以理解为then
方法的实例,即在resolve
和reject
里面的公共操作函数
all
方法
用于将多个 Promise
实例,包装成一个新的 Promise
实例。它接收一个具有Iterator
接口的参数。其中,item
如果不是Promise
对象,会自动调用Promise.resolve
方法
以下代码:
1 const p = Promise .all([p1, p2, p3]);
对于Promise.all()
包装的Promise
对象,只有实例的状态都变成fulfilled
。
可以用来操作数据库:
1 2 3 4 5 6 7 8 9 const databasePromise = connectDatabase();const booksPromise = databasePromise.then(findAllBooks);const userPromise = databasePromise.then(getCurrentUser);Promise .all([booksPromise, userPromise]).then(([books, user] ) => pickTopRecommentations(books, user) );
或者其中有一个变为rejected
,才会调用Promise.all
方法后面的回调函数。而对于每个promise
对象,一旦它被自己定义catch
方法捕获异常,那么状态就会更新为resolved
而不是rejected
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 "use strict" ;const p1 = new Promise ((resolve, reject ) => { resolve("hello" ); }) .then(result => result) .catch(e => e); const p2 = new Promise ((resolve, reject ) => { throw new Error ("p2 error" ); }) .then(result => result) .catch( e => e.message ); Promise .all([p1, p2]) .then( result => console .log(result) ) .catch( e => console .log("error in all" ) );
race方法
和all
方法类似,Promise.race
方法同样是将多个 Promise
实例,包装成一个新的 Promise
实例。而且只要有一个状态被改变,那么新的Promise
状态会立即改变
也是来自阮一峰大大的例子,如果 5 秒内无法fetech
,那么p
状态就会变为rejected
。
1 2 3 4 5 6 7 8 const p = Promise .race([ fetch("/resource-that-may-take-a-while" ), new Promise (function (resolve, reject ) { setTimeout (() => reject(new Error ("request timeout" )), 5000 ); }) ]); p.then(response => console .log(response)); p.catch(error => console .log(error));
重要性质 状态只改变一次
Promise
的状态一旦改变,就永久保持该状态,不会再变了。
下面代码中,Promise
对象resolved
后,状态就无法再变成rejected
了。
1 2 3 4 5 6 7 8 9 10 11 12 13 "use strict" ;const promise = new Promise ((resolve, reject ) => { resolve("ok" ); throw new Error ("test" ); }); promise .then(val => { console .log(val); }) .catch(error => { console .log(error.message); });
错误冒泡
Promise
对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止 。也就是说,错误总是会被下一个catch
语句捕获
“吃掉错误”机制
Promise
会吃掉内部的错误,并不影响外部代码的运行。所以需要catch
,以防丢掉错误信息。
阮一峰大大给出的 demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 "use strict" ;const someAsyncThing = function ( ) { return new Promise (function (resolve, reject ) { resolve(x + 2 ); }); }; someAsyncThing().then(function ( ) { console .log("everything is great" ); }); setTimeout (() => { console .log(123 ); }, 2000 );
还有如下 demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 someAsyncThing() .then(function ( ) { return someOtherAsyncThing(); }) .catch(function (error ) { console .log("oh no" , error); y + 2 ; }) .catch(function (error ) { console .log("carry on" , error); });
参考
demo 基本可以在阮一峰的 Es6 讲解 中找到,只是为了理解做了一些修改。
还有网上的一些博客,这里就不一一说明了