mirror of
https://github.com/apachecn/eloquent-js-3e-zh.git
synced 2025-05-23 20:02:20 +00:00
11.
This commit is contained in:
parent
a5f565c196
commit
ef450a8d38
98
11.md
98
11.md
@ -211,7 +211,7 @@ function request(nest, target, type, content) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
因为承诺只能解析(或拒绝)一次,所以这个是有效的。 第一次调用`resolve`或`reject`会决定`Promise`的结果,并且任何进一步的调用(例如请求结束后到达的超时,或在另一个请求结束后返回的请求)都将被忽略。
|
因为`Promise`只能解析(或拒绝)一次,所以这个是有效的。 第一次调用`resolve`或`reject`会决定`Promise`的结果,并且任何进一步的调用(例如请求结束后到达的超时,或在另一个请求结束后返回的请求)都将被忽略。
|
||||||
|
|
||||||
为了构建异步循环,对于重试,我们需要使用递归函数 - 常规循环不允许我们停止并等待异步操作。 `attempt`函数尝试发送请求一次。 它还设置了超时,如果 250 毫秒后没有响应返回,则开始下一次尝试,或者如果这是第四次尝试,则以`Timeout`实例为理由拒绝该`Promise`。
|
为了构建异步循环,对于重试,我们需要使用递归函数 - 常规循环不允许我们停止并等待异步操作。 `attempt`函数尝试发送请求一次。 它还设置了超时,如果 250 毫秒后没有响应返回,则开始下一次尝试,或者如果这是第四次尝试,则以`Timeout`实例为理由拒绝该`Promise`。
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ function requestType(name, handler) {
|
|||||||
|
|
||||||
每台鸟巢计算机在其`neighbors`属性中,都保存了传输距离内的其他鸟巢的数组。 为了检查当前哪些可以访问,您可以编写一个函数,尝试向每个鸟巢发送一个`"ping"`请求(一个简单地请求响应的请求),并查看哪些返回了。
|
每台鸟巢计算机在其`neighbors`属性中,都保存了传输距离内的其他鸟巢的数组。 为了检查当前哪些可以访问,您可以编写一个函数,尝试向每个鸟巢发送一个`"ping"`请求(一个简单地请求响应的请求),并查看哪些返回了。
|
||||||
|
|
||||||
在处理同时运行的`Promise`集合时,`Promise.all`函数可能很有用。 它返回一个`Promise`,等待数组中的所有`Promise`解决,然后解析这些`Promise`产生的值的数组(与原始数组的顺序相同)。 如果任何`Promise`被拒绝,`Promise.all`的结果本身被拒绝。
|
在处理同时运行的`Promise`集合时,`Promise.all`函数可能很有用。 它返回一个`Promise`,等待数组中的所有`Promise`解析,然后解析这些`Promise`产生的值的数组(与原始数组的顺序相同)。 如果任何`Promise`被拒绝,`Promise.all`的结果本身被拒绝。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
requestType("ping", () => "pong");
|
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");
|
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!");
|
||||||
|
```
|
||||||
|
|
||||||
|
我们已经在原始通信系统的基础上构建了几层功能,来使其便于使用。 这是一个(尽管是简化的)真实计算机网络工作原理的很好的模型。
|
||||||
|
|
||||||
|
计算机网络的一个显着特点是它们不可靠 - 建立在它们之上的抽象可以提供帮助,但是不能抽象出网络故障。所以网络编程通常关于预测和处理故障。
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user