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 20:56:14 +08:00
parent a5f565c196
commit ef450a8d38

98
11.md
View File

@ -211,7 +211,7 @@ function request(nest, target, type, content) {
}
```
因为承诺只能解析(或拒绝)一次,所以这个是有效的。 第一次调用`resolve``reject`会决定`Promise`的结果,并且任何进一步的调用(例如请求结束后到达的超时,或在另一个请求结束后返回的请求)都将被忽略。
因为`Promise`只能解析(或拒绝)一次,所以这个是有效的。 第一次调用`resolve``reject`会决定`Promise`的结果,并且任何进一步的调用(例如请求结束后到达的超时,或在另一个请求结束后返回的请求)都将被忽略。
为了构建异步循环,对于重试,我们需要使用递归函数 - 常规循环不允许我们停止并等待异步操作。 `attempt`函数尝试发送请求一次。 它还设置了超时,如果 250 毫秒后没有响应返回,则开始下一次尝试,或者如果这是第四次尝试,则以`Timeout`实例为理由拒绝该`Promise`
@ -245,7 +245,7 @@ function requestType(name, handler) {
每台鸟巢计算机在其`neighbors`属性中,都保存了传输距离内的其他鸟巢的数组。 为了检查当前哪些可以访问,您可以编写一个函数,尝试向每个鸟巢发送一个`"ping"`请求(一个简单地请求响应的请求),并查看哪些返回了。
在处理同时运行的`Promise`集合时,`Promise.all`函数可能很有用。 它返回一个`Promise`,等待数组中的所有`Promise`,然后解析这些`Promise`产生的值的数组(与原始数组的顺序相同)。 如果任何`Promise`被拒绝,`Promise.all`的结果本身被拒绝。
在处理同时运行的`Promise`集合时,`Promise.all`函数可能很有用。 它返回一个`Promise`,等待数组中的所有`Promise`,然后解析这些`Promise`产生的值的数组(与原始数组的顺序相同)。 如果任何`Promise`被拒绝,`Promise.all`的结果本身被拒绝。
```js
requestType("ping", () => "pong");
@ -294,7 +294,7 @@ requestType("gossip", (nest, message, source) => {
});
```
为了避免永远在网络上发送相同的消息,每个鸟巢都保留一组已经看到的闲话串。 为了定义这个数组,我们使用`everywhere`函数(它在每个鸟巢上运行代码)向鸟巢的状态对象添加一个属性,这是我们将保鸟巢局部状态的地方。
为了避免永远在网络上发送相同的消息,每个鸟巢都保留一组已经看到的闲话字符串。 为了定义这个数组,我们使用`everywhere`函数(它在每个鸟巢上运行代码)向鸟巢的状态对象添加一个属性,这是我们将保鸟巢局部状态的地方。
当一个鸟巢收到一个重复的闲话消息,它会忽略它。每个人都盲目重新发送这些消息时,这很可能发生。 但是当它收到一条新消息时,它会兴奋地告诉它的所有邻居,除了发送消息的那个邻居。
@ -308,3 +308,95 @@ requestType("gossip", (nest, message, source) => {
sendGossip(bigOak, "Kids with airgun in the park");
```
## 消息路由
如果给定节点想要与其他单个节点通信,泛洪不是一种非常有效的方法。 特别是当网络很大时,这会导致大量无用的数据传输。
另一种方法是为消息设置节点到节点的传输方式,直到它们到达目的地。 这样做的困难在于,它需要网络布局的知识。 为了向远方的鸟巢发送请求,有必要知道哪个邻近的鸟巢更靠近其目的地。 以错误的方向发送它不会有太大好处。
由于每个鸟巢只知道它的直接邻居,因此它没有计算路线所需的信息。 我们必须以某种方式,将这些连接的信息传播给所有鸟巢。 当放弃或建造新的鸟巢时,最好是允许它随时间改变的方式。
我们可以再次使用泛洪,但不检查给定的消息是否已经收到,而是检查对于给定鸟巢来说,邻居的新集合,是否匹配我们拥有的当前集合。
```js
requestType("connections", (nest, {name, neighbors},
source) => {
let connections = nest.state.connections;
if (JSON.stringify(connections.get(name)) ==
JSON.stringify(neighbors)) return;
connections.set(name, neighbors);
broadcastConnections(nest, name, source);
});
function broadcastConnections(nest, name, exceptFor = null) {
for (let neighbor of nest.neighbors) {
if (neighbor == exceptFor) continue;
request(nest, neighbor, "connections", {
name,
neighbors: nest.state.connections.get(name)
});
}
}
everywhere(nest => {
nest.state.connections = new Map;
nest.state.connections.set(nest.name, nest.neighbors);
broadcastConnections(nest, nest.name);
});
```
该比较使用`JSON.stringify`,因为对象或数组上的`==`只有在两者完全相同时才返回`true`,这不是我们这里所需的。 比较 JSON 字符串是比较其内容的一种简单而有效的方式。
节点立即开始广播它们的连接,它们应该立即为每个鸟巢提供当前网络图的映射,除非有一些鸟巢完全无法到达。
你可以用图做的事情,就是找到里面的路径,就像我们在第 7 章中看到的那样。如果我们有一条通往消息目的地的路线,我们知道将它发送到哪个方向。
这个`findRoute`函数非常类似于第 7 章中的`findRoute`,它搜索到达网络中给定节点的路线。 但不是返回整个路线,而是返回下一步。 下一个鸟巢将使用它的有关网络的当前信息,来决定将消息发送到哪里。
```js
function findRoute(from, to, connections) {
let work = [{at: from, via: null}];
for (let i = 0; i < work.length; i++) {
let {at, via} = work[i];
for (let next of connections.get(at) || []) {
if (next == to) return via;
if (!work.some(w => w.at == next)) {
work.push({at: next, via: via || next});
}
}
}
return null;
}
```
现在我们可以建立一个可以发送长途信息的函数。 如果该消息被发送给直接邻居,它将照常发送。 如果不是,则将其封装在一个对象中,并使用`"route"`请求类型,将其发送到更接近目标的邻居,这将导致该邻居重复相同的行为。
```js
function routeRequest(nest, target, type, content) {
if (nest.neighbors.includes(target)) {
return request(nest, target, type, content);
} else {
let via = findRoute(nest.name, target,
nest.state.connections);
if (!via) throw new Error(`No route to ${target}`);
return request(nest, via, "route",
{target, type, content});
}
}
requestType("route", (nest, {target, type, content}) => {
return routeRequest(nest, target, type, content);
});
```
我们现在可以将消息发送到教堂塔楼的鸟巢中,它的距离有四跳。
```js
routeRequest(bigOak, "Church Tower", "note",
"Incoming jackdaws!");
```
我们已经在原始通信系统的基础上构建了几层功能,来使其便于使用。 这是一个(尽管是简化的)真实计算机网络工作原理的很好的模型。
计算机网络的一个显着特点是它们不可靠 - 建立在它们之上的抽象可以提供帮助,但是不能抽象出网络故障。所以网络编程通常关于预测和处理故障。