【问题标题】:Prevent js alert() from pausing timers防止 js alert() 暂停计时器
【发布时间】:2008-10-13 15:47:22
【问题描述】:

所以我为测验做了一些计时器。问题是,当我放

javascript: alert("blah");

在地址中,弹出警告框暂停我的计时器。这在测验中是非常不受欢迎的。

我认为没有任何方法可以阻止这种行为......但我还是会问。

如果没有,介意建议我该怎么做?

【问题讨论】:

    标签: javascript timer


    【解决方案1】:

    永远不要依赖 javascript(或任何其他客户端时间)来计算在回发或不同页面之间完成的操作所经过的时间。

    如果你总是比较服务器日期,人们就很难作弊:

    1. 首页请求,存储服务器时间
    2. 每 N 秒使用 javascript 调用一次,比较 2 个服务器时间,并返回经过的时间(仅供展示)
    3. 当用户提交表单时,比较两个服务器时间,计算经过的时间,丢弃耗时过长的(即:可能的作弊者)

    【讨论】:

      【解决方案2】:

      显然预览渲染与发布的渲染不同。这一段是为了确保接下来的两行显示为代码。

      // Preserve native alert() if you need it for something special
      window.nativeAlert = window.alert;
      
      window.alert = function(msg) {
          // Do something with msg here. I always write mine to console.log,
          // but then I have rarely found a use for a real modal dialog,
          // and most can be handled by the browser (like window.onbeforeunload).
      };
      

      【讨论】:

      • 注意:虽然我知道警报仍然可以通过 javascript 访问:nativeAlert();但至少它需要查看源代码和一些 JS 理解而不是盲目尝试 alert();
      • 您也可以将 nativeAlert 包装在一个闭包中以使其私有。
      • 这很好,但正确的答案是 Filini 的。始终假设不在您立即控制下的浏览器已损坏、被操纵等。我所说的“即时控制”是指在 BEAT-WITH-STICK 距离内。
      • 同意,实际上。但我确实想直接回答具体问题(如何覆盖警报)。
      【解决方案3】:

      不,没有办法阻止警报停止 JavaScript 中的单线程。也许您可以使用其他一些用户通知方式,例如浮动层。

      【讨论】:

      • 实际上确实如此,这似乎是一个两部分的问题 - 1)我可以停止这种行为吗? 2)如果没有,我还能做些什么来显示通知?
      【解决方案4】:

      它是模态的并停止执行。考虑一种不会像 Lightbox 技术那样暂停执行的替代方案。

      【讨论】:

        【解决方案5】:

        我认为提问者试图防止作弊。由于用户可以键入 javascript: alert("paused");进入地址栏,或者做一个小书签来做,很容易暂停测验和作弊。

        我唯一能想到的是使用 Date() 来获取当前时间,并在计时器触发时再次检查它。然后,如果时间差没有合理地接近预期的计时器持续时间,请发出警告并取消该问题的答案或让他们通过测验。没有办法阻止用户暂停您的测验,但应该可以抓住他们。

        当然,通过任何防作弊功能,您都会激励人们成为更好的作弊者。一个人可以在他们的 PC 上更改系统时间,并欺骗从操作系统获取时间的 javascript Date() 构造函数。

        您可以使用时间间隔与一秒的时间间隔长度进行重复的时钟比较。间隔处理程序还可以更新用户显示器上的剩余时间字段。然后,随着测验时间的流逝,用户可以感受到压力的增加。欢乐时光!

        【讨论】:

        • 很高兴您提出这个问题。我之前没有考虑过使用警报作为暂停按钮。也很高兴你问,因为选择的答案是我以前从未见过的。现在我可以通过让自己成为一个警报书签来在定时 javascript 测验中作弊! (直到他们阅读此页面)
        【解决方案6】:

        关于 SyaZ 问题的反馈循环澄清了相关问题。

        这里尝试总结一下到目前为止的好答案:

        • 客户端脚本本质上很容易被操纵以欺骗在线测验。见@Filini 's Server-side approach

        • window.alert = function(msg) {} 将覆盖 alert() 并且可能会击败放入地址栏的低悬果实:javascript:alert('Pausing页面,以便我可以用谷歌搜索答案')或者我现在使用我的电话朋友。Courtesy of @eyelidlessness

        • 如果您必须使用客户端方法,而不是使用 setTimeOut(),您可以使用自定义的基于日期比较的暂停函数,例如(concept by @Mnebuerquo,我的代码示例(@micahwittman )):

        例子:

        var beginDate = new Date();
        
        function myTimeout(milsecs){
          do { curDate = new Date(); }
            while((curDate-beginDate) < milsecs);
        }
        
        function putDownYourPencils(milsecs){
          myTimeout(milsecs);
          var seconds = milsecs / 1000;
          alert('Your '  + seconds + ' seconds are up. Quiz is over.');
        }
        
        putDownYourPencils(3000);
        

        【讨论】:

          【解决方案7】:

          最终,您无法信任用户输入。如果不跟踪服务器上经过的时间,就不能保证数据没有被操纵。

          但是,如果您确信您的测验者不精通 JavaScript,并且只是依靠他们在某处发现的“技巧”,您可以使用以下代码测试作弊(暂停),这不会' t需要修改window.alert:

          var timer = {
              startDatetime: null,
              startSec: 0,
              variance: 1,
              exitOnPause: true,
              count: function (config) {
                  var that = this;
          
                  if (typeof config == "object" && typeof parseInt(config.seconds) == "number" && !isNaN(parseInt(config.seconds)))
                  {
                      if (typeof parseFloat(config.variance) == "number" && !isNaN(parseFloat(config.variance))) this.variance = config.variance;
                      if (typeof config.exitOnPause == "boolean") this.exitOnPause = config.exitOnPause;
          
                      if (config.seconds > 0)
                      {
                          if (!this.startSec) this.startSec = config.seconds;
                          if (!this.startDatetime) this.startDatetime = new Date();
                          var currentDatetime = new Date();
          
                          if (currentDatetime.getTime() - this.startDatetime.getTime() > (this.startSec - config.seconds) * this.variance * 1000)
                          {
                              if (typeof config.onPause == "function") config.onPause();
          
                              if (!this.exitOnPause)
                              {
                                  this.startDatetime = new Date();
                                  this.startSec = config.seconds--;
                                  window.setTimeout(function () { that.count(config); }, 1000);
                              }
                          }
                          else
                          {
                              config.seconds--;
                              window.setTimeout(function () { that.count(config); }, 1000);
                          }
                      }
                      else
                      {
                          if (typeof config.onFinish == "function") config.onFinish();
                      }
                  }
              }
          };
          

          这个计时器对象有一个方法 count(),它接受一个对象作为输入。它期望输入对象中至少有一个 seconds 属性。

          由于某种原因,window.setTimeout 并不总是按预期工作。有时,在我的机器上,应该在 1 秒后执行代码的 window.setTimeout(x, 1000) 花费了 2 秒以上。因此,在这种情况下,您应该允许差异,这样没有作弊的人就不会被标记为作弊者。方差默认为 1,但可以在输入对象中覆盖。下面是如何使用此代码的示例,它允许 2.5 秒的“摆动空间”用于慢戳:

          timer.count({
              seconds: 10,
              onPause: function () { alert("You cheated!"); window.location.replace("cheatersAreBad.html"); },
              onFinish: function () { alert("Time's up!"); },
              variance: 2.5
          });
          

          通过这样的解决方案,您可以使用 Ajax 告诉服务器端脚本用户已暂停计时器或将用户重定向到解释他们被发现作弊的页面。如果出于某种原因,您希望允许用户在被发现作弊后继续参加测验,您可以将 exitOnPause 设置为 false:

          timer.count({
              seconds: 10,
              exitOnPause: false,
              onPause: function () { recordCheaterViaAjax(); },
              onFinish: function () { alert("Time's up!"); },
              variance: 2.5
          });
          

          【讨论】:

            【解决方案8】:

            可以将服务器会话设置为在 1 小时后到期。 javascript 只能用作显示工具,让用户知道还剩多少时间。如果他决定通过暂停计时器来作弊,那么在发布他的测试时他可能会惊讶于他的会话已超时。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-04-25
              • 1970-01-01
              • 2014-04-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多