1
0
mirror of https://github.com/apachecn/eloquent-js-3e-zh.git synced 2025-05-23 20:02:20 +00:00
This commit is contained in:
wizardforcel 2018-05-10 12:22:36 +08:00
parent 882d5522e5
commit f287ae6d23

58
11.md
View File

@ -113,3 +113,61 @@ defineRequestType("note", (nest, content, source, done) => {
某种程度上,异步性是传染的。任何调用异步的函数的函数,本身都必须是异步的,使用回调或类似的机制来传递其结果。调用回调函数比简单地返回一个值更容易出错,所以以这种方式构建程序的较大部分并不是很好。
## `Promise`
当这些概念可以用值表示时,处理抽象概念通常更容易。 在异步操作的情况下,你不需要安排将来某个时候调用的函数,而是返回一个代表这个未来事件的对象。
这是标准类`Promise`的用途。 `Promise`是一种异步行为,可以在某个时刻完成并产生一个值。 当值可用时,它能够通知任何感兴趣的人。
创建`Promise`的最简单方法是调用`Promise.resolve`。 这个函数确保你给它的值包含在一个`Promise`中。 如果它已经是`Promise`,那么仅仅返回它 - 否则,你会得到一个新的`Promise`,并使用你的值立即结束。
```js
let fifteen = Promise.resolve(15);
fifteen.then(value => console.log(`Got ${value}`));
// → Got 15
```
为了获得`Promise`的结果,可以使用它的`then`方法。 它注册了一个回调函数,当`Promise`解析并产生一个值时被调用。 您可以将多个回调添加到单个`Promise`中,即使在`Promise`解析(完成)后添加它们,它们也会被调用。
但那不是`then`方法所做的一切。 它返回另一个`Promise`,它解析处理器函数返回的值,或者如果返回`Promise`,则等待该`Promise`,然后解析为结果。
`Promise`视为一种手段,将值转化为异步现实,是有用处的。 一个正常的值就在那里。promised 的值是未来可能存在或可能出现的值。 根据`Promise`定义的计算对这些包装值起作用,并在值可用时异步执行。
为了创建`Promise`,你可以将`Promise`用作构造器。 它有一个有点奇怪的接口 - 构造器接受一个函数作为参数,它会立即调用,并传递一个函数来解析这个`Promise`。 它以这种方式工作,而不是使用`resolve`方法,这样只有创建`Promise`的代码才能解析它。
这就是为`readStorage`函数创建基于`Promise`的接口的方式。
```js
function storage(nest, name) {
return new Promise(resolve => {
nest.readStorage(name, result => resolve(result));
});
}
storage(bigOak, "enemies")
.then(value => console.log("Got", value));
```
这个异步函数返回一个有意义的值。 这是`Promise`的主要优点 - 它们简化了异步函数的使用。 基于`Promise`的函数不需要传递回调,而是类似于常规函数:它们将输入作为参数并返回它们的输出。 唯一的区别是输出可能还不可用。
## 失败
常规的 JavaScript 计算可能会因抛出异常而失败。 异步计算经常需要类似的东西。 网络请求可能会失败,或者作为异步计算的一部分的某些代码,可能会引发异常。
异步编程的回调风格中最紧迫的问题之一是,确保将失败正确地报告给回调函数,是非常困难的。
一个广泛使用的约定是,回调函数的第一个参数用于指示操作失败,第二个参数包含操作成功时生成的值。 这种回调函数必须始终检查它们是否收到异常,并确保它们引起的任何问题,包括它们调用的函数所抛出的异常,都会被捕获并提供给正确的函数。
`Promise`使这更容易。可以解决它们(操作成功完成)或拒绝(失败)。只有在操作成功时,才会调用解析处理器(使用`then`注册),并且拒绝会自动传播给由`then`返回的新`Promise`。当一个处理器抛出一个异常时,这会自动使`then`调用产生的`Promise`被拒绝。因此,如果异步操作链中的任何元素失败,则整个链的结果被标记为拒绝,并且不会调用失败位置之后的任何常规处理器。
就像`Promise`的解析提供了一个值,拒绝它也提供了一个值,通常称为拒绝的原因。当处理器中的异常导致拒绝时,异常值将用作原因。同样,当处理器返回被拒绝的`Promise`时,拒绝流入下一个`Promise``Promise.reject`函数会创建一个新的,立即被拒绝的`Promise`
为了明确地处理这种拒绝,`Promise`有一个`catch`方法,用于注册一个处理器,当`Promise`被拒绝时被调用,类似于处理器处理正常解析的方式。 这也非常类似于`then`,因为它返回一个新的`Promise`,如果它正常解析,它将解析原始`Promise`的值,否则返回`catch`处理器的结果。 如果`catch`处理器抛出一个错误,新的`Promise`也被拒绝。
作为简写,`then`还接受拒绝处理器作为第二个参数,因此您可以在单个方法调用中,装配这两种的处理器。
传递给`Promise`构造器的函数接收第二个参数,并与解析函数一起使用,它可以用来拒绝新的`Promise`
通过调用`then``catch`创建的`Promise`值的链条,可以看作异步值或失败沿着它移动的流水线。 由于这种链条通过注册处理器来创建,因此每个链条都有一个成功处理器或与其关联的拒绝处理器(或两者都有)。 不匹配结果类型(成功或失败)的处理器将被忽略。 但是那些匹配的对象被调用,并且它们的结果决定了下一次会出现什么样的值 -- 返回非`Promise`值时成功,当它抛出异常时拒绝,并且当它返回其中一个时是`Promise`的结果。
就像环境处理未捕获的异常一样JavaScript 环境可以检测未处理`Promise`拒绝的时候,并将其报告为错误。