How to handle/generate client errors or results when using latency compensation?


#1

Hi,

I have read through the latency compensation chapter in discover meteor, as well as these 2 following articles on latency compensation:

  1. advanced latency compensation
  2. two tiered methods

From my understanding, latency compensation allows a piece of code to run on both the client and the server asynchronously. It is typically useful for things that can benefit from optimistic UI or fast response times (e.g. someone clicking on an upvote).

And a basic latency compensation pattern typically looks like the following:

Meteor.call("latencyCompensationFunction", function(error, result){
  if (error) {
    // server has thrown some error
    // do some error handling here
  else {
    // server has returned some result
    // do some stuff with result here
  }
});

Seems like we can handle any errors or results return by the server via the associating anonymous callback function.

But how do we handle any errors or results returned by the client during the “latencyCompensationFunction” call? Or can we at all?

for example:

Meteor.methods({
  latencyCompensationFunction: function(input) {
    // ... do something with input ...
    if (error) {
      if (Meteor.isServer) {
        throw Meteor.Error(...);
      }
      else if (Meteor.isClient) {
        // What do we do here? 
        // Do we throw an error as well? 
        // If we throw an error here, wouldn't the calling function see the same error twice?
      }
    }
  }
});

Or am I misunderstanding how latency compensation works?

Any tips, pointers, or links to further reading on this topic would be much appreciated.


#2

You can catch the error thrown by Meteor.Error on the client, and deal with it there. No need to catch it inside the method itself, I think.


#3

Hi Sacha,

Thanks for your reply! I was a bit star struck when I saw your reply :blush:

Can you explain what you mean by “You can catch the error thrown by Meteor.Error on the client, and deal with it there.” I don’t quite understand what you mean by that.

Also, I came across this article, Smooth error handling for Meteor.methods, where it stated that one should return an error on the client side and throw an error on the server side.

For example:

Meteor.methods({
  latencyCompensationFunction: function(input) {
    // ... do something with input ...
    if (error) {
      if (Meteor.isServer) {
        throw Meteor.Error(...);
      }
      else if (Meteor.isClient) {
        return Meteor.Error(...)
      }
    }
  }
});
Meteor.call("latencyCompensationFunction", function(error, result){
  if (error) {
    // do some error handling here
  else {
    // do some stuff with result here
  }
});

I tried that pattern, and the anonymous callback function captured the error thrown by the server perfectly well. However, the callback function didn’t capture the error returned by the client, and that error seems to have disappeared into thin air. I have no idea where the client error went.

Any thoughts or idea on why that’s the case?

Btw, thank you for writing discovering meteor. It has helped me a ton on learning meteor js.


#4

Check the undocumented returnStubValue argument.

See:


#5

Meteor.Error is the only exception sent back over the wire to the client (meteor docs).
In methods you use Meteor.isSimulation to distinguish between the stub method and the server. I think you also should actually create the Error with new

throw new Meteor.Error(...);

#6

The returnStubValue function is good to know. Thanks Steve!

Do you know of any specific use cases where one would prefer to results returned by returnStubValue vs results returned by the server?


#7

Thanks jamgold. It seems like there is no [good] way to capture any errors return by the client during from the client/simulation part of latency compensation.

Would you say that the best practice would be to do error handling from the client before calling latencyCompensation functions?


#8

Whenever possible, you should always use returnStubValue to makes your UI more reactive instead of waiting for the server response. This is called “latency compensation” in Meteor.

A typical use case is a method that inserts a new element in a collection: you want to call it and immediately route the URL to the returned id.

In fact, it is strange returnStubValue is not true by default. There is a package called grove:call-sync, which somehow makes it the default behavior (not tested).


#9

thanks very good to know. Thank you for the advice!