setTimeout 花费的时间比应有的时间长

2023-12-30

有人可以解释一下为什么下面的脚本setTimeout命令,在 Greasemonkey 中执行的时间(400-500 毫秒)比在 Firefox 控制台中执行的时间要长得多(在 Firefox 控制台中正好是 100 毫秒)?

var start = new Date ().getTime ();
console.log (
    new Date ().getHours ()+" : " + new Date ().getMinutes () 
    + " : " + new Date ().getSeconds () + " : " 
    + new Date ().getMilliseconds () 
); 

setTimeout (foo,100);
//foo ();

function foo () {
    var time = new Date () - start;
    console.log ("Execution time: " + time + "ms");
}

这很奇怪,因为如果我切换setTimeout(foo,100)为了一个纯粹的foo(),Greasemonkey 和 Firefox 控制台都以闪电般的速度执行(约 10 毫秒)。


实际上,在我的临时系统(Win XP、FF 28.0、GM 1.15)上,这与 Greasemonkey 关系不大,而与 (A) 控制台和 (B) Firefox 和/或您的机器正在执行的其他操作有关。

JavaScript 定时器是出了名的糟糕 https://stackoverflow.com/q/196027/331508。 (也可以看看,John Resig 的“JavaScript 时间的准确性” http://ejohn.org/blog/accuracy-of-javascript-time/.)

您的结果基于非常小的样本量,并且没有足够的数据来开始看到准确的情况。此外,浏览器和 Greasemonkey 已针对此问题进行了更改,因此您的版本可能会有所不同。

如果我们使用区间,EG:

setInterval (foo, 100);

function foo () {
    var time = new Date () - start;
    console.log ("Execution time: " + time + "ms");
}

然后我们就可以开始收集一些统计数据,看看会发生什么。

完善该代码并添加统计信息可以得到如下的用户脚本:

// ==UserScript==
// @name        _Greasemonkey timing test
// @include     https://stackoverflow.com/questions/22738493/*
// @grant       none
// ==/UserScript==
// @grant       GM_addStyle

/*--- Test:
        Both grant modes
        FF console
        Firebug console
        Embedded in page.
*/
var numMeasurements = 100;
var measurementList = [];
var startDate       = new Date ();
var startTime       = startDate.getTime ();

console.log (
    startDate.getHours ()+ " : " + startDate.getMinutes () + " : "
    + startDate.getSeconds () + " : " + startDate.getMilliseconds ()
);

var startDate   = new Date ();  //-- Record time just before interval start.
//setTimeout (timelog, 100);
/*--- WARNING: for delays less than about 50, system "granularity" and
    overhead effects will distort the results even more.
*/
var logTimer    = setInterval (timelog, 100);

function timelog () {
    timelog.numloops    = timelog.numloops  ||  0;

    if (timelog.numloops >= numMeasurements) {
        console.log ('===> Reached ' + timelog.numloops + ' loops.');
        clearInterval (logTimer);

        //--- Calculate stats:
        var stats           = {};
        stats.min           = Number.MAX_VALUE; //-- Always start at opposite
        stats.max           = Number.MIN_VALUE;
        stats.sum           = 0;
        stats.mean          = 0;
        stats.sumSqrs       = 0;
        stats.stdDev        = 0;
        stats.N             = measurementList.length;

        for (var J = 0;  J < stats.N;  ++J) {
            var measVal     = measurementList[J];
            stats.sum      += measVal;
            stats.sumSqrs  += measVal * measVal;

            if (measVal > stats.max)    stats.max = measVal;
            if (measVal < stats.min)    stats.min = measVal;
        }

        stats.mean          = stats.sum / stats.N;
        stats.stdDev        = Math.sqrt (
            (stats.sumSqrs / stats.N) - (stats.mean * stats.mean)
        );


        //--- Display stats:
        var decsToDisplay   = 1;
        console.log (' Measurements: ' + stats.N);
        console.log ('      Average: ' + stats.mean.toFixed (decsToDisplay) );
        console.log ('   Min to Max: ' + stats.min + ' to ' + stats.max);
        console.log ('Std Deviation: ' + stats.stdDev.toFixed (decsToDisplay) );
    }
    else {
        timelog.numloops++;
        var timeNow = new Date ();
        var timeDif = timeNow - startDate;
        measurementList.push (timeDif);
        console.log (
            '==> Execution time ('
              //-- Left-pad value for more legible column, 3 chars wide.
            + ("  " + timelog.numloops).slice (-3) + '): '
              //-- Left-pad value for more legible column, 4 chars wide.
            + ("   " + timeDif).slice (-4) + ' ms   '
            , timeNow.getTime ()
        );
        startDate   = timeNow;
    }
}


安装脚本和/或者您可以在 jsFiddle 中查看此代码的实际运行情况 http://jsfiddle.net/caL94/2/.

要了解 Greasemonkey 是否是一个因素,我们应该进行测试at least这些场景:

  1. Firefox 控制台中的代码。
  2. 在控制台和关闭控制台的情况下在网页中编写代码。
  3. 沙箱处于活动状态的 Greasemonkey 脚本中的代码(@grant GM_addStyle set).
  4. Greasemonkey 脚本中的代码@grant none active.
  5. Firebug 控制台中的代码。

理想情况下,网页和系统环境应尽可能保持不变。

使用 100 毫秒延迟和 100 个样本(可能是有意义数据的最小值)进行测试,我得到(所有值以毫秒为单位):



//-- These first were run against stackoverflow.com/q/22738493

                                                  Std
Condition                      Min  Max   Avg   Deviation
--------------------------     ---  ---  -----  ---------
Firefox console, run 1:          0  518  138.9    133.2
Firefox console, run 2:          1  466  215.4    209.6

Firebug console, run 1:          1  144  100.5     21.8
Firebug console, run 2:          3  209  100.9     25.2

GM to FF cons, in sandbox:       0  398  135.4    112.9
GM to FF cons, @grant none 1:    0  387  125.3     97.4
GM to FF cons, @grant none 2:    0  563  145.2    122.0
GM to Firebug console:          38  401  109.4     49.1

//-- These were run against jsfiddle.net/caL94/2

jsFiddle to FF console 1:        2  375  113.3     82.5
jsFiddle to FF console 2:        1  575  169.7    171.1
jsFiddle to Firebug console:    27  219  103.5     24.9

jsFiddle, consoles closed 1:     0  530  105.3     57.2
jsFiddle, consoles closed 2:     5  195  100.0     21.9
  


从这些数字应该可以清楚地看出:

  1. JavaScript 计时器不利于精确计时。(但它们可能足以满足大多数实际的网页用途。)
  2. Greasemonkey 中的计时代码的执行效果与在 Firebug 控制台中运行或不记录到任何控制台的代码一样好。
  3. The real big hit is logging to Firefox's console (CtrlShiftK) -- which radically decreases timer accuracy.
  4. 计算机和浏览器(甚至网页)状态都在很大程度上影响准确性和可重复性。
  5. 另外,请记住如果您离开选项卡,浏览器会限制 JavaScript 计时器 https://stackoverflow.com/q/15871942/331508(失去焦点)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

setTimeout 花费的时间比应有的时间长 的相关文章

随机推荐

  • 根据一列删除重复项并在 Google 表格中保留最新条目

    我正在研究一些自动化 并希望通过根据第三列进行比较来删除我的谷歌工作表中的重复行 我发现一个代码可以完美运行 但它不会删除工作表中的旧条目 而是删除最新的条目 我想保留最新的而不是重复的 这是我为 appscript 找到的代码Cooper
  • Python - 如何使该代码异步?

    这是一些说明我的问题的代码 def blocking1 while True yield first blocking function example def blocking2 while True yield second block
  • SmartGWT ListGrid 很慢,但仅限于 Internet Explorer

    我们已经从 gwtext 迁移到 SmartGWT 总体体验还不错 然而 我们在使用 SmartGWT 的 ListGrid 组件时遇到了很大的问题 如果满足以下两个条件 则速度非常慢 使用 Internet Explorer 5 列或更多
  • 如何在 Django 模型中存储字符串数组?

    我正在构建一个 Django 数据模型 并且希望能够在其中一个变量中存储一组字符串 我怎样才能做到这一点 e g class myClass models Model title models CharField max length 50
  • 将 BLOB(图像)从 oracle 导入到 hive

    我正在尝试使用下面的 Sqoop 命令将 BLOB Image 数据从 oracle 导入到 Hive sqoop import connect jdbc oracle thin host username password m 3 tab
  • 使用 Fusion Table 时有哪些技术限制?

    我正在寻找有关使用 Fusion Tables 时的技术限制的信息 Fusion Table 中可以存储多少行 可以针对 Fusion Table 同时运行多少个查询 读 写 我找不到任何信息https developers google
  • 在 HTML 末尾或“onload”时初始化 JS 组件?

    有一段时间 我一直在通过等待 onload 事件触发并执行一个 JavaScript 组件初始化来运行main 各种各样的 它看起来更干净 并且您可以确定 DOM 的 ID 状态是有序的 但经过一段时间的测试后 我发现组件的初始化被加载期间
  • 编码为 JSON 时 Golang 错误类型为空

    我正在尝试为 REST api 编码一些 JSON 除了一些错误之外 一切正常 例如 使用以下结构 type TemplateResponse struct Message string Error error Template Templ
  • R -应用-将许多列从数字转换为因子

    我需要将许多数字列转换为因子类型 示例表 df lt data frame A 1 10 B 2 11 C 3 12 我尝试过应用 cols lt c A B df cols lt apply df cols 2 function x as
  • WP7 Bing 地图图钉 - 如何调整自定义图钉的位置?

    好吧 简单的问题 但我还没有找到明显简单的答案 我有一个带有地图集成的 Windows Phone 7 应用程序 地图上有一组图钉 图钉是定制的 只是椭圆形 圆形 不幸的是 自定义图钉的位置与地理位置 偏离 当你放大时 它会越来越接近准确
  • 可重复使用的Barrier解决方案陷入僵局?

    我一直在读 The Little Book of Semaphores 第 41 页有一个针对可重用屏障问题的解决方案 我遇到的问题是为什么它不会产生死锁情况 1 rendezvous 2 3 mutex wait 4 count 1 5
  • 安装 PECL 包时出错:Mysql_xdevapi

    当我运行此命令时出现以下错误 sudo pecl install mysql xdevapi Error private tmp pear temp pear build nabilashahidhnTBCl mysql xdevapi 8
  • 将项目添加到组合框

    我正在尝试向组合框添加一些项目 如 msdn 网站上所示 但它向我抛出空引用异常 comboBox1 Items Add test 我尝试将其更改为 ComboBox combobox1 new ComboBox object test n
  • Log4j2 找不到我的配置文件

    我正在尝试设置 SLF4J 以与 Log4J2 一起使用 但我不断收到此错误 ERROR StatusLogger No log4j2 configuration file found Using default configuration
  • Laravel Eloquent:如何从连接表中仅获取某些列

    我在 Eloquent 中有 2 个连接表 即主题和用户 主题模型 public function user return this gt belongs to User 用户模型 public function themes return
  • RecyclerView:未连接适配器;跳过布局

    我一直在 stackoverflow 和 this 上阅读不同的答案博客文章 http blog ashwanik in 2015 05 handling adapter error while using recyclerview htm
  • 搜索包含西里尔文数据的 SQLite 数据库

    我在搜索 SQLite 数据库时遇到问题 该数据库包含用西里尔字符编写的数据 如果关键字也是西里尔字母 那么一切正常 但如果不是 那么我无法在 Android 应用程序中获得结果 有谁知道如何实现搜索西里尔文数据 无论关键字的字符集如何 谢
  • 将 C++ 程序转换为 Windows 服务?

    我编写了一个 做事 的控制台程序 主要使用 boost 如何将其转换为 Windows 服务 关于 Windows 服务 我应该提前了解哪些信息 MSDN 上有一个关于如何设置最小服务的好例子 http msdn microsoft com
  • 在文本中使用 sympy 打印希腊字母

    假设我想打印类似的东西 我是圆周率 其中 pi 实际上应该是希腊字母 pi 带着同情心我可以做到 import sympy from sympy abc import pi sympy pprint pi 它给出了希腊字母 pi 但我在将其
  • setTimeout 花费的时间比应有的时间长

    有人可以解释一下为什么下面的脚本setTimeout命令 在 Greasemonkey 中执行的时间 400 500 毫秒 比在 Firefox 控制台中执行的时间要长得多 在 Firefox 控制台中正好是 100 毫秒 var star