我在 PWA 中使用以下代码,根据文档计算客户端相对于 Firebase 实时数据库服务器的时钟偏差:-
var offsetRef = firebase.database().ref(".info/serverTimeOffset");
offsetRef.on("value", function(snap) {
var offset = snap.val();
var estimatedServerTimeMs = new Date().getTime() + offset;
});
但是,问题是,在某些设备上,我会得到奇怪的值,例如 -13181 的偏移量,使其延迟了近 13 秒!因此,该设备上的 20 秒倒计时器从 7 秒开始,因为实际上偏移量要低得多。昨天,一台机器始终获得上述值(-13181),尽管它之前运行良好。同一网络上的设备是否会报告时间偏移值存在如此巨大的差异?我该如何解决这个问题?在不同设备之间同步的倒计时器对于我的应用程序非常重要。
最佳答案
添加我们昨天谈话的背景,你说:
We made a quiz application where even thousands of people can play in real time and so everyone has to see the same value on the countdown timer. Our logic is working pretty well except for the fact that rarely I get strange offset values.
您不想尽可能依赖客户端的时钟。根据人们的网络质量和与服务器的距离,已经不可避免地存在一些差异,因此正如您所看到的,添加不可靠的本地时钟可能会加剧这种情况。在线游戏的计时不是一件小事,我不会声称拥有最好的解决方案,但这里有一个尝试建议:
拥有一个事实来源,比如服务器,它可以跟踪游戏的剩余时间并在数据库中更新它。您可以使用 Firebase Admin SDK从您的服务器访问数据库,这可能就是您现在输入时间戳的方式。
从 Admin SDK 写入数据库将如下所示:
admin.database().ref(".info/timeRemaining").set({
time_remaining: time_remaining
});
其中 time_remaining
是您每秒更新的时间。
然后在客户端上,您只需剩余时间,而不是跟踪偏移量。
var offsetRef = firebase.database().ref(".info/timeRemaining");
offsetRef.on("value", function(snap) {
var offset = snap.val();
// do what you will
});
然后你可以在客户端制定以 0 结束游戏的规则。当然开发者可以找到解决这个问题的方法,所以如果可能的话,最好包含一个服务器检查。如果客户端也在写入数据库,但您不希望它们在超过时间限制后能够写入,则一种选择是使用规则。现在,您的规则将根据您的数据结构而有所不同。我只是推测将写入应用于 ".info"
的任何子级,这可能并不完全是您所需要的。
{
"rules": {
".info": {
"$info": {
".read": "auth != null",
// writes can only happen before the timer reaches 0
".write": "data.parent().child('time_remaining').val() > 0"
}
}
}
}
此规则仅允许用户在 time_remaining
的值大于 0 时写入该位置。如果他们尝试在此之后写入,将返回错误,您可以处理在客户端。
关于Firebase 实时数据库给出了不正确的服务器时间偏移值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50361600/