» gRPC快速入门:Node.js » 5. 创建 client » 5.2 调用服务方法

调用服务方法

现在看看如何调用服务方法。注意,所有方法都是异步的:它们使用 events(事件)和 callbacks(回调)来获取结果。

简单 RPC

调用简单 RPC GetFeature 几乎和调用本地异步方法一样简单。

var point = {latitude: 409146138, longitude: -746188906};
stub.getFeature(point, function(err, feature) {
  if (err) {
    // process error
  } else {
    // process feature
  }
});

如你所见,我们创建并填充了一个请求对象。最后,我们调用 stub 上的方法,将请求和回调传递给它。如果没有错误,我们j就可以从响应对象中读取服务器的响应信息。

console.log('Found feature called "' + feature.name + '" at ' +
    feature.location.latitude/COORD_FACTOR + ', ' +
    feature.location.longitude/COORD_FACTOR);

服务端流式 RPC

现在让我们来看看流式方法。如果你已经阅读了创建 server 部分,其中一些可能看起来非常相似。流式 RPC 在两端都以类似的方式实现。 以下调用服务端流式方法 ListFeatures 的代码,它返回地理信息 Feature 的流:

var call = client.listFeatures(rectangle);
  call.on('data', function(feature) {
      console.log('Found feature called "' + feature.name + '" at ' +
          feature.location.latitude/COORD_FACTOR + ', ' +
          feature.location.longitude/COORD_FACTOR);
  });
  call.on('end', function() {
    // server 已经完成发送
  });
  call.on('error', function(e) {
    // 出现错误,流被关闭
  });
  call.on('status', function(status) {
    // 处理结果状态
  });

与前文传递请求和回调函数给方法不同,我们传递了一个请求并收到一个 Readable(可读)流对象作为返回。客户端可以使用 Readable'data' 事件来读取服务器的响应。每次收到一个 Feature 消息对象时,该事件都会触发,直到没有更多的消息为止。 在 'data' 回调中的错误不会导致流被关闭。'error' 事件表示发生了错误并且流已关闭。'end' 事件表示服务器已完成发送且没有错误发生。'error''end' 二者中只会触发一个。最后,当服务器发送状态时,'status' 事件会被触发。

客户端流式 RPC

客户端流式方法 RecordRoute 与服务器端方法类似,不同之处在于我们传递了回调函数并获得了一个 Writable 流。

var call = client.recordRoute(function(error, stats) {
  if (error) {
    callback(error);
  }
  console.log('Finished trip with', stats.point_count, 'points');
  console.log('Passed', stats.feature_count, 'features');
  console.log('Travelled', stats.distance, 'meters');
  console.log('It took', stats.elapsed_time, 'seconds');
});
function pointSender(lat, lng) {
  return function(callback) {
    console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
        lng/COORD_FACTOR);
    call.write({
      latitude: lat,
      longitude: lng
    });
    _.delay(callback, _.random(500, 1500));
  };
}
var point_senders = [];
for (var i = 0; i < num_points; i++) {
  var rand_point = feature_list[_.random(0, feature_list.length - 1)];
  point_senders[i] = pointSender(rand_point.location.latitude,
                                 rand_point.location.longitude);
}
async.series(point_senders, function() {
  call.end();
});

一旦我们使用 write() 将客户端的请求都写入流中,我们需要调用 end() 来告诉 gRPC 我们已经完成了写入。如果结果状态是 OK,那么 stats 对象就会被服务端的响应正确填充。

双向流式 RPC

最后,让我们看看双向流式 RPC routeChat()。我们直接调用 routeChat() 并获得一个 Duplex 流对象。它可以用于写入和读取消息。

var call = client.routeChat();
call.on('data', function(note) {
    // ...
});

call.on('end', callback);

...

for (var i = 0; i < notes.length; i++) {
    var note = notes[i];
    call.write(note);
}
call.end();

这里的读取和写入语法与客户端、服务端流式方法非常相似,尽管两端始终按照其写入顺序收到另一方的消息,但是客户端和服务端都可以按任意顺序读取和写入 - 各自的流完全独立运行。