Skip to content

Commit e5b3208

Browse files
committed
docs(promise): add Promise.try()
1 parent ff35ad8 commit e5b3208

File tree

2 files changed

+127
-13
lines changed

2 files changed

+127
-13
lines changed

docs/promise.md

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,12 +509,12 @@ Promise.all([
509509
`Promise.race`方法同样是将多个Promise实例,包装成一个新的Promise实例。
510510

511511
```javascript
512-
var p = Promise.race([p1,p2,p3]);
512+
var p = Promise.race([p1, p2, p3]);
513513
```
514514

515-
上面代码中,只要`p1``p2``p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给`p`的回调函数。
515+
上面代码中,只要`p1``p2``p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给`p`的回调函数。
516516

517-
`Promise.race`方法的参数与`Promise.all`方法一样,如果不是Promise实例,就会先调用下面讲到的`Promise.resolve`方法,将参数转为Promise实例,再进一步处理。
517+
`Promise.race`方法的参数与`Promise.all`方法一样,如果不是 Promise 实例,就会先调用下面讲到的`Promise.resolve`方法,将参数转为 Promise 实例,再进一步处理。
518518

519519
下面是一个例子,如果指定时间内没有获得结果,就将Promise的状态变为`reject`,否则变为`resolve`
520520

@@ -768,3 +768,115 @@ run(g);
768768

769769
上面代码的Generator函数`g`之中,有一个异步操作`getFoo`,它返回的就是一个`Promise`对象。函数`run`用来处理这个`Promise`对象,并调用下一个`next`方法。
770770

771+
## Promise.try()
772+
773+
实际开发中,经常遇到一种情况:不知道函数`f`是同步函数,还是异步操作,但是想用 Promise 来处理它。因为这样就可以不管`f`是否包含异步操作,都用`then`方法指定下一步流程,用`catch`方法处理`f`抛出的错误。一般就会采用下面的写法。
774+
775+
```javascript
776+
Promise.resolve().then(f)
777+
```
778+
779+
上面的写法有一个缺点,就是如果`f`是同步函数,那么它会在下一轮事件循环执行。
780+
781+
```javascript
782+
const f = () => console.log('now');
783+
Promise.resolve().then(f);
784+
console.log('next');
785+
// next
786+
// now
787+
```
788+
789+
上面代码中,函数`f`是同步的,但是用 Promise 包装了以后,就变成异步执行了。
790+
791+
那么有没有一种方法,让同步函数同步执行,异步函数异步执行,并且让它们具有统一的 API 呢?回答是可以的,并且还有两种写法。第一种写法是用`async`函数来写。
792+
793+
```javascript
794+
const f = () => console.log('now');
795+
(async () => f())();
796+
console.log('next');
797+
// now
798+
// next
799+
```
800+
801+
上面代码中,第一行是一个立即执行的匿名函数,会立即执行里面的`async`函数,因此如果`f`是同步的,就会得到同步的结果;如果`f`是异步的,就可以用`then`指定下一步,就像下面的写法。
802+
803+
```javascript
804+
(async () => f())()
805+
.then(...)
806+
```
807+
808+
需要注意的是,`async () => f()`会吃掉`f()`抛出的错误。所以,如果想捕获错误,要使用`promise.catch`方法。
809+
810+
```javascript
811+
(async () => f())()
812+
.then(...)
813+
.catch(...)
814+
```
815+
816+
第二种写法是使用`new Promise()`
817+
818+
```javascript
819+
const f = () => console.log('now');
820+
(
821+
() => new Promise(
822+
resolve => resolve(f())
823+
)
824+
)();
825+
console.log('next');
826+
// now
827+
// next
828+
```
829+
830+
上面代码也是使用立即执行的匿名函数,执行`new Promise()`。这种情况下,同步函数也是同步执行的。
831+
832+
鉴于这是一个很常见的需求,所以现在有一个[提案](https://github.com/ljharb/proposal-promise-try),提供`Promise.try`方法替代上面的写法。
833+
834+
```javascript
835+
const f = () => console.log('now');
836+
Promise.try(f);
837+
console.log('next');
838+
// now
839+
// next
840+
```
841+
842+
事实上,`Promise.try`存在已久,Promise 库[`Bluebird`](http://bluebirdjs.com/docs/api/promise.try.html)[`Q`](https://github.com/kriskowal/q/wiki/API-Reference#promisefcallargs)[`when`](https://github.com/cujojs/when/blob/master/docs/api.md#whentry),早就提供了这个方法。
843+
844+
由于`Promise.try`为所有操作提供了统一的处理机制,所以如果想用`then`方法管理流程,最好都用`Promise.try`包装一下。这样有[许多好处](http://cryto.net/~joepie91/blog/2016/05/11/what-is-promise-try-and-why-does-it-matter/),其中一点就是可以更好地管理异常。
845+
846+
```javascript
847+
function getUsername(userId) {
848+
return database.users.get({id: userId})
849+
.then(function(user) {
850+
return uesr.name;
851+
});
852+
}
853+
```
854+
855+
上面代码中,`database.users.get()`返回一个 Promise 对象,如果抛出异步错误,可以用`catch`方法捕获,就像下面这样写。
856+
857+
```javascript
858+
database.users.get({id: userId})
859+
.then(...)
860+
.catch(...)
861+
```
862+
863+
但是`database.users.get()`可能还会抛出同步错误(比如数据库连接错误,具体要看实现方法),这时你就不得不用`try...catch`去捕获。
864+
865+
```javascript
866+
try {
867+
database.users.get({id: userId})
868+
.then(...)
869+
.catch(...)
870+
} catch (e) {
871+
// ...
872+
}
873+
```
874+
875+
上面这样的写法就很笨拙了,这时就可以统一用`promise.catch()`捕获所有同步和异步的错误。
876+
877+
```javascript
878+
Promise.try(database.users.get({id: userId}))
879+
.then(...)
880+
.catch(...)
881+
```
882+

docs/reference.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@
127127
- Axel Rauschmayer, [Pitfall: not all objects can be wrapped transparently by proxies](http://www.2ality.com/2016/11/proxying-builtins.html)
128128
- Bertalan Miklos, [Writing a JavaScript Framework - Data Binding with ES6 Proxies](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/): 使用 Proxy 实现观察者模式
129129

130+
## Promise对象
131+
132+
- Jake Archibald, [JavaScript Promises: There and back again](http://www.html5rocks.com/en/tutorials/es6/promises/)
133+
- Tilde, [rsvp.js](https://github.com/tildeio/rsvp.js)
134+
- Sandeep Panda, [An Overview of JavaScript Promises](http://www.sitepoint.com/overview-javascript-promises/): ES6 Promise入门介绍
135+
- Dave Atchley, [ES6 Promises](http://www.datchley.name/es6-promises/): Promise的语法介绍
136+
- Axel Rauschmayer, [ECMAScript 6 promises (2/2): the API](http://www.2ality.com/2014/10/es6-promises-api.html): 对ES6 Promise规格和用法的详细介绍
137+
- Jack Franklin, [Embracing Promises in JavaScript](http://javascriptplayground.com/blog/2015/02/promises/): catch 方法的例子
138+
- Ronald Chen, [How to escape Promise Hell](https://medium.com/@pyrolistical/how-to-get-out-of-promise-hell-8c20e0ab0513#.2an1he6vf): 如何使用`Promise.all`方法的一些很好的例子
139+
- Jordan Harband, [proposal-promise-try](https://github.com/ljharb/proposal-promise-try): Promise.try() 方法的提案
140+
- Sven Slootweg, [What is Promise.try, and why does it matter?](http://cryto.net/~joepie91/blog/2016/05/11/what-is-promise-try-and-why-does-it-matter/): Promise.try() 方法的优点
141+
130142
## Iterator
131143

132144
- Mozilla Developer Network, [Iterators and generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators)
@@ -154,16 +166,6 @@
154166
- Axel Rauschmayer, [ES6 generators in depth](http://www.2ality.com/2015/03/es6-generators.html): Generator规格的详尽讲解
155167
- Derick Bailey, [Using ES6 Generators To Short-Circuit Hierarchical Data Iteration](https://derickbailey.com/2015/10/05/using-es6-generators-to-short-circuit-hierarchical-data-iteration/):使用 for...of 循环完成预定的操作步骤
156168

157-
## Promise对象
158-
159-
- Jake Archibald, [JavaScript Promises: There and back again](http://www.html5rocks.com/en/tutorials/es6/promises/)
160-
- Tilde, [rsvp.js](https://github.com/tildeio/rsvp.js)
161-
- Sandeep Panda, [An Overview of JavaScript Promises](http://www.sitepoint.com/overview-javascript-promises/): ES6 Promise入门介绍
162-
- Dave Atchley, [ES6 Promises](http://www.datchley.name/es6-promises/): Promise的语法介绍
163-
- Axel Rauschmayer, [ECMAScript 6 promises (2/2): the API](http://www.2ality.com/2014/10/es6-promises-api.html): 对ES6 Promise规格和用法的详细介绍
164-
- Jack Franklin, [Embracing Promises in JavaScript](http://javascriptplayground.com/blog/2015/02/promises/): catch方法的例子
165-
- Ronald Chen, [How to escape Promise Hell](https://medium.com/@pyrolistical/how-to-get-out-of-promise-hell-8c20e0ab0513#.2an1he6vf): 如何使用`Promise.all`方法的一些很好的例子
166-
167169
## 异步操作和Async函数
168170

169171
- Luke Hoban, [Async Functions for ECMAScript](https://github.com/lukehoban/ecmascript-asyncawait): Async函数的设计思想,与Promise、Gernerator函数的关系

0 commit comments

Comments
 (0)