- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有以下代码演示了直接从事件触发器调用长时间运行的函数与使用 setTimeout()
的区别。
预期行为:
当按下第一个按钮时,它显示为按下,计算运行几秒钟,然后当计算完成时,按钮再次显示为按下,第二列从“尚未计算”变为“计算完成” ”。 (我不会详细说明为什么会发生这种情况;it's explained in linked answer。)
按下第二个按钮时,按钮立即按下;第二列立即变为“正在计算...”文本。数秒后计算完成时,第二列从“正在计算...”变为“计算完成”。
实际发生了什么:
这在 Chrome 中完美运行(两个按钮都按预期运行)
这在 Internet Explorer 8 中非常有效
这在 Firefox (v.25) 中不起作用。具体来说,第二个按钮的行为与第一个按钮 100% 相同。
将 setTimeout()
中的超时从 0
更改为 1
无效
将 setTimeout()
中的超时从 0
更改为 500
有效
这给我留下了一个大难题。
根据 setTimeout()
有效而缺少一个无效的全部原因,延迟对工作方式的影响应该为零,因为 setTimeout()
的主要目的是改变这里的排队顺序,而不是拖延事情。
那么,为什么它不能在 Firefox 上使用延迟 0 或 1,但可以按预期使用延迟 500(并且可以在 Internet Explorer 8/Chrome 上使用任何延迟)?
更新:除了下面的源代码,我还制作了一个 JSFiddle .但出于某种原因,JSFiddle 甚至拒绝在我的 Internet Explorer 8 上加载,因此对于该测试,需要以下代码。
更新 2:有人提出 Firefox 中配置设置 dom.min_timeout_value
存在问题的可能性。我已经将它从 4 编辑到 0,重新启动浏览器,但没有任何问题得到修复。它仍然会因超时 0 或 1 而失败,并在 500 时成功。
这是我的源代码 - 我只是将它保存到 C: 驱动器上的 HTML 文件并在所有三种浏览器中打开:
<html><body>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<table border=1>
<tr><td><button id='do'>Do long calc - bad status!</button></td>
<td><div id='status'>Not Calculating yet.</div></td></tr>
<tr><td><button id='do_ok'>Do long calc - good status!</button></td>
<td><div id='status_ok'>Not Calculating yet.</div></td></tr>
</table>
<script>
function long_running(status_div) {
var result = 0;
for (var i = 0; i < 1000; i++) {
for (var j = 0; j < 700; j++) {
for (var k = 0; k < 200; k++) {
result = result + i + j + k;
}
}
}
$(status_div).text('calclation done');
}
// Assign events to buttons
$('#do').on('click', function () {
$('#status').text('calculating....');
long_running('#status');
});
$('#do_ok').on('click', function () {
$('#status_ok').text('calculating....');
window.setTimeout(function (){ long_running('#status_ok') }, 0);
});
</script>
</body></html>
要进行测试,您需要将 Internet Explorer 8 的嵌套循环边界更改为 300/100/100;或 Chrome 的 1000/1000/500,这是由于“此 JS 花费的时间太长”错误的不同敏感性以及 JavaScript 引擎速度。
最佳答案
在 Ubuntu 中有一份当前(2016 年 6 月 28 日)window.setTimeout()
实现的副本。
正如我们所见,定时器是通过这行代码插入的:
nsAutoPtr<TimeoutInfo>* insertedInfo =
mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
然后几行下面有一个if()
语句:
if (insertedInfo == mTimeouts.Elements() && !mRunningExpiredTimeouts) {
...
insertedInfo == mTimeouts.Elements()
检查刚刚插入的定时器是否已经超时。以下 block 不执行附加函数,但主循环会立即注意到计时器超时,因此它将跳过您期望的 IDLE 状态(CPU 的产出)。
这清楚地(至少对我而言)解释了您正在经历的行为。屏幕上的渲染是另一个进程(任务/线程),需要放弃 CPU 以便其他进程有机会重新绘制屏幕。为此,您需要等待足够长的时间,这样您的计时器函数就不会立即执行并发生 yield。
正如您所注意到的,暂停 500 毫秒就可以了。您或许可以使用较小的数字,例如 50 毫秒。无论哪种方式,它都不能保证产生 yield ,但如果运行该代码的计算机当前没有被淹没(即反病毒当前没有在后台全速运行...... )
来自 Firefox 的完整 SetTimeout()
函数:
(文件在源码中的位置:dom/workers/WorkerPrivate.cpp
)
int32_t
WorkerPrivate::SetTimeout(JSContext* aCx,
dom::Function* aHandler,
const nsAString& aStringHandler,
int32_t aTimeout,
const Sequence<JS::Value>& aArguments,
bool aIsInterval,
ErrorResult& aRv)
{
AssertIsOnWorkerThread();
const int32_t timerId = mNextTimeoutId++;
Status currentStatus;
{
MutexAutoLock lock(mMutex);
currentStatus = mStatus;
}
// It's a script bug if setTimeout/setInterval are called from a close handler
// so throw an exception.
if (currentStatus == Closing) {
JS_ReportError(aCx, "Cannot schedule timeouts from the close handler!");
}
// If the worker is trying to call setTimeout/setInterval and the parent
// thread has initiated the close process then just silently fail.
if (currentStatus >= Closing) {
aRv.Throw(NS_ERROR_FAILURE);
return 0;
}
nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
newInfo->mIsInterval = aIsInterval;
newInfo->mId = timerId;
if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
NS_WARNING("Timeout ids overflowed!");
mNextTimeoutId = 1;
}
// Take care of the main argument.
if (aHandler) {
newInfo->mTimeoutCallable = JS::ObjectValue(*aHandler->Callable());
}
else if (!aStringHandler.IsEmpty()) {
newInfo->mTimeoutString = aStringHandler;
}
else {
JS_ReportError(aCx, "Useless %s call (missing quotes around argument?)",
aIsInterval ? "setInterval" : "setTimeout");
return 0;
}
// See if any of the optional arguments were passed.
aTimeout = std::max(0, aTimeout);
newInfo->mInterval = TimeDuration::FromMilliseconds(aTimeout);
uint32_t argc = aArguments.Length();
if (argc && !newInfo->mTimeoutCallable.isUndefined()) {
nsTArray<JS::Heap<JS::Value>> extraArgVals(argc);
for (uint32_t index = 0; index < argc; index++) {
extraArgVals.AppendElement(aArguments[index]);
}
newInfo->mExtraArgVals.SwapElements(extraArgVals);
}
newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
if (!newInfo->mTimeoutString.IsEmpty()) {
if (!nsJSUtils::GetCallingLocation(aCx, newInfo->mFilename, &newInfo->mLineNumber)) {
NS_WARNING("Failed to get calling location!");
}
}
nsAutoPtr<TimeoutInfo>* insertedInfo =
mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
LOG(TimeoutsLog(), ("Worker %p has new timeout: delay=%d interval=%s\n",
this, aTimeout, aIsInterval ? "yes" : "no"));
// If the timeout we just made is set to fire next then we need to update the
// timer, unless we're currently running timeouts.
if (insertedInfo == mTimeouts.Elements() && !mRunningExpiredTimeouts) {
nsresult rv;
if (!mTimer) {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;
}
mTimerRunnable = new TimerRunnable(this);
}
if (!mTimerRunning) {
if (!ModifyBusyCountFromWorker(true)) {
aRv.Throw(NS_ERROR_FAILURE);
return 0;
}
mTimerRunning = true;
}
if (!RescheduleTimeoutTimer(aCx)) {
aRv.Throw(NS_ERROR_FAILURE);
return 0;
}
}
return timerId;
}
重要提示: JavaScript 指令 yield
与我所说的无关。我说的是 sched_yield()当二进制进程调用某些函数时发生的功能,例如 sched_yield()
本身、poll()
、select()
等
关于javascript - 为什么这个基于 setTimeout 的代码不能在 Firefox 中以小超时工作(在 Internet Explorer/Chrome 中工作)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20747591/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!