简体   繁体   中英

Firebase.ServerValue.TIMESTAMP not synched between listeners and the client that actually adds data

Here is the simplest example possible:

var fb = new Firebase('https://xxxxxxxxxxx.firebaseio.com/test');

fb.limitToLast(1).on('child_added', function(snap) {
    console.log('key', snap.key());
    console.log('val', snap.val());
});

fb.push({
    date_now: Firebase.ServerValue.TIMESTAMP
});

If I open two tabs with this script, the one that actually pushes data gets local timestamp in child_added callback and the other tab that just listens gets proper server-generated one. As far as I understand it's done to exclude round-trip and save bandwidth.

But for my task this behaviour is unacceptable. How can I overcome it?

This is the console.log from pusher:

key -K59mrvEUhTaoNIQQoA4
val Object {date_now: 1449732570832}

and listeners (equals to server data seen in dashboard):

key -K59mrvEUhTaoNIQQoA4
val Object {date_now: 1449732571759}

Firebase fires two local events for that write operation:

  1. it immediately fires a child_added event with the local timestamp (corrected for your expected offset to the server)
  2. it later fires a child_changed event with the actual timestamp as the server specified it.

So you can solve the problem by listening for both events:

var fb = new Firebase('https://xxxxxxxxxxx.firebaseio.com/test');

var query = fb.limitToLast(1);
query.on('child_added', function(snap) {
    console.log('key', snap.key());
    console.log('val', snap.val());
});
query.on('child_changed', function(snap) {
    console.log('key', snap.key());
    console.log('val', snap.val());
});

fb.push({
    date_now: Firebase.ServerValue.TIMESTAMP
});

In general it is recommended to handle all child_* events and not just child_added . There may be more reasons why the server has to update or remove the value, to correct for the local event.

If you prefer having a single callback/event handler, you can also listen for the value event:

var query = fb.limitToLast(1);
query.on('value', function(snap) {
    snap.forEach(function(child) {
        console.log('key', child.key());
        console.log('val', child.val());
    });
});

You'll note the use of forEach() in the callback.

For the Realtime SDK this is the expected behavior. Eventually, the timestamp will reflect the proper server value. But, if this does not suit your needs you can use the REST API.

function addTimestamp() {
  fetch('https://<my-firebase-app>.firebaseio.com/test/.json', {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      '.sv': 'timestamp' // add a timestamp
    })
  });
}

This will not use the local timestamp, and in combination with the Realtime SDK, each client will have the same timestamp on the first update.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM