9

概括

清除表单输入中的文本会导致 Chrome 出现长时间延迟(几秒)。似乎这会导致计算样式的重排或重新计算,但我不确定。Chrome 的 Profiler 和 Timeline 没有提供任何信息。

是什么导致延迟?我怎样才能消除它?这是我的代码中的错误,还是 Chrome 中的错误?

例子

http://jsfiddle.net/jmilloy/dHFsQ/

要导致延迟,请在输入中键入,然后删除文本。当您删除最后一个字符或全选然后删除时,会出现延迟。

要消除延迟,请使用、或row4代替。现在您可以清除输入而不会造成延迟。row1row2row3

笔记

  • 延迟取决于n行数。

  • 它出现在 Chrome 中,但不在 Firefox 中。

  • 它发生在 Linux(Ubuntu/Mint 11)和 Windows 7 中,但不是 OSX。任何人都可以确认吗?


一旦我有一个表现出延迟行为的jsfiddle,我就完全重写了这个问题,并用一个更简单的例子再次重写。

4

3 回答 3

7

这似乎是WebKit中的性能错误或ICU中的解析错误,可能两者兼而有之,但我倾向于认为问题出在 WebKit 中。

我在 OS X 上从源代码构建 Chromium并验证构建存在问题。目前尚不清楚为什么它没有出现在 OS X 上的 Chrome 中。我在您的测试页面上分析了渲染器进程,发现它大部分时间都花在 ICU 中的函数RuleBasedBreakIterator::handleNext()RuleBasedBreakIterator::handlePrevious(). 这是一个典型的堆栈跟踪:

Program received signal SIGINT, Interrupt.
icu_46::RuleBasedBreakIterator::handleNext (this=0x6a1f4600, statetable=0xafdbb50) at ../../third_party/icu/source/common/rbbi.cpp:1085
1085            if (state == STOP_STATE) {
(gdb) where
#0  icu_46::RuleBasedBreakIterator::handleNext (this=0x6a1f4600, statetable=0xafdbb50) at ../../third_party/icu/source/common/rbbi.cpp:1085
#1  0x09c2048f in icu_46::RuleBasedBreakIterator::next (this=0x6a1f4600) at ../../third_party/icu/source/common/rbbi.cpp:535
#2  0x09c23a30 in icu_46::RuleBasedBreakIterator::following (this=0x6a1f4600, offset=2377) at ../../third_party/icu/source/common/rbbi.cpp:693
#3  0x09c50399 in ubrk_following_46 (bi=0x6a1f4600, offset=2377) at ../../third_party/icu/source/common/ubrk.cpp:254
#4  0x03112489 in WebCore::textBreakFollowing (iterator=0x6a1f4600, pos=2377) at ../../third_party/WebKit/Source/WebCore/platform/text/TextBreakIteratorICU.cpp:380
#5  0x03111276 in WebCore::findNextWordFromIndex (chars=0x69a7a000, len=2848, position=2377, forward=true) at ../../third_party/WebKit/Source/WebCore/platform/text/TextBoundaries.cpp:77
#6  0x016352d3 in WebCore::nextWordPositionBoundary (characters=0x69a7a000, length=2848, offset=0, mayHaveMoreContext=WebCore::MayHaveMoreContext, needMoreContext=@0xc00078b2) at ../../third_party/WebKit/Source/WebCore/editing/VisibleUnits.cpp:695
#7  0x0163498a in WebCore::nextBoundary (c=@0xc0008440, searchFunction=0x1635220 <WebCore::nextWordPositionBoundary(unsigned short const*, unsigned int, unsigned int, WebCore::BoundarySearchContextAvailability, bool&)>) at ../../third_party/WebKit/Source/WebCore/editing/VisibleUnits.cpp:575
#8  0x016351c5 in WebCore::nextWordPosition (c=@0xc0008440) at ../../third_party/WebKit/Source/WebCore/editing/VisibleUnits.cpp:700
#9  0x0159d2ce in WebCore::Editor::updateMarkersForWordsAffectedByEditing (this=0x6abca710, doNotRemoveIfSelectionAtWordBoundary=true) at ../../third_party/WebKit/Source/WebCore/editing/Editor.cpp:2398
#10 0x0159ce7c in WebCore::Editor::respondToChangedContents (this=0x6abca710, endingSelection=@0xc0008578) at ../../third_party/WebKit/Source/WebCore/editing/Editor.cpp:556
#11 0x0159fa81 in WebCore::Editor::appliedEditing (this=0x6abca710, cmd=@0xc00085f0) at ../../third_party/WebKit/Source/WebCore/editing/Editor.cpp:863
#12 0x0162597a in WebCore::TypingCommand::typingAddedToOpenCommand (this=0x6a570fb0, commandTypeForAddedTyping=WebCore::TypingCommand::DeleteKey) at ../../third_party/WebKit/Source/WebCore/editing/TypingCommand.cpp:347
#13 0x01622e05 in WebCore::TypingCommand::deleteKeyPressed (this=0x6a570fb0, granularity=WebCore::CharacterGranularity, killRing=false) at ../../third_party/WebKit/Source/WebCore/editing/TypingCommand.cpp:525
#14 0x01621bfa in WebCore::TypingCommand::deleteKeyPressed (document=0x6abcc200, options=0, granularity=WebCore::CharacterGranularity) at ../../third_party/WebKit/Source/WebCore/editing/TypingCommand.cpp:120
#15 0x0159b945 in WebCore::Editor::deleteWithDirection (this=0x6abca710, direction=WebCore::DirectionBackward, granularity=WebCore::CharacterGranularity, killRing=false, isTypingAction=true) at ../../third_party/WebKit/Source/WebCore/editing/Editor.cpp:382
#16 0x015b5cc8 in WebCore::executeDeleteBackward (frame=0x6abca200) at ../../third_party/WebKit/Source/WebCore/editing/EditorCommand.cpp:339
#17 0x015b4e7f in WebCore::Editor::Command::execute (this=0xc0008c28, parameter=@0xc0008c20, triggeringEvent=0x0) at ../../third_party/WebKit/Source/WebCore/editing/EditorCommand.cpp:1706
#18 0x0419f8c4 in WebKit::WebFrameImpl::executeCommand (this=0x6a31f770, name=@0xc0008ca0, value=@0xc0008c98) at ../../third_party/WebKit/Source/WebKit/chromium/src/WebFrameImpl.cpp:1245
#19 0x07d5e3a1 in content::RenderViewImpl::handleCurrentKeyboardEvent (this=0x6a998000) at ../../content/renderer/render_view_impl.cc:2189
#20 0x07d5e452 in non-virtual thunk to content::RenderViewImpl::handleCurrentKeyboardEvent() (this=0x6a998314) at ../../content/renderer/render_view_impl.cc:2195
#21 0x040f97dc in WebKit::EditorClientImpl::handleKeyboardEvent (this=0x6a9ba674, evt=0x190468e0) at ../../third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp:645
#22 0x01599799 in WebCore::Editor::handleKeyboardEvent (this=0x6abca710, event=0x190468e0) at ../../third_party/WebKit/Source/WebCore/editing/Editor.cpp:212
#23 0x01a9713d in WebCore::EventHandler::defaultKeyboardEventHandler (this=0x6abca854, event=0x190468e0) at ../../third_party/WebKit/Source/WebCore/page/EventHandler.cpp:3325
#24 0x07790701 in WebCore::Node::defaultEventHandler (this=0x19049eb0, event=0x190468e0) at ../../third_party/WebKit/Source/WebCore/dom/Node.cpp:2475
#25 0x048aa253 in WebCore::HTMLTextFormControlElement::defaultEventHandler (this=0x19049eb0, event=0x190468e0) at ../../third_party/WebKit/Source/WebCore/html/HTMLTextFormControlElement.cpp:111
#26 0x0480cf5f in WebCore::HTMLInputElement::defaultEventHandler (this=0x19049eb0, evt=0x190468e0) at ../../third_party/WebKit/Source/WebCore/html/HTMLInputElement.cpp:1159
#27 0x0772ac59 in WebCore::EventDispatcher::dispatchEventPostProcess (this=0xc0009048, preDispatchEventHandlerResult=0x0) at ../../third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:208
#28 0x07729cc6 in WebCore::EventDispatcher::dispatch (this=0xc0009048) at ../../third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:127
#29 0x07728b03 in WebCore::EventDispatchMediator::dispatchEvent (this=0x190f6f90, dispatcher=0xc0009048) at ../../third_party/WebKit/Source/WebCore/dom/EventDispatchMediator.cpp:54
#30 0x07728f50 in WebCore::EventDispatcher::dispatchEvent (node=0x19049eb0, mediator=@0xc0009130) at ../../third_party/WebKit/Source/WebCore/dom/EventDispatcher.cpp:56
#31 0x0778f078 in WebCore::Node::dispatchEvent (this=0x19049eb0, event=@0xc0009198) at ../../third_party/WebKit/Source/WebCore/dom/Node.cpp:2351
#32 0x077405e1 in WebCore::EventTarget::dispatchEvent (this=0x19049eb0, event=@0xc00092e8, ec=@0xc00092e0) at ../../third_party/WebKit/Source/WebCore/dom/EventTarget.cpp:147
#33 0x01a9688a in WebCore::EventHandler::keyEvent (this=0x6abca854, initialKeyEvent=@0xc00093c0) at ../../third_party/WebKit/Source/WebCore/page/EventHandler.cpp:3207
#34 0x04236521 in WebKit::WebViewImpl::handleKeyEvent (this=0x6a9ba600, event=@0x1900f2e8) at ../../third_party/WebKit/Source/WebKit/chromium/src/WebViewImpl.cpp:1003
#35 0x04236def in non-virtual thunk to WebKit::WebViewImpl::handleKeyEvent(WebKit::WebKeyboardEvent const&) (this=0x6a9ba628, event=@0x1900f2e8) at ../../third_party/WebKit/Source/WebKit/chromium/src/WebViewImpl.cpp:1015
#36 0x0413554d in WebKit::PageWidgetDelegate::handleInputEvent (page=0x6a9baa00, handler=@0x6a9ba628, event=@0x1900f2e8) at ../../third_party/WebKit/Source/WebKit/chromium/src/PageWidgetDelegate.cpp:144
#37 0x0423bebb in WebKit::WebViewImpl::handleInputEvent (this=0x6a9ba600, inputEvent=@0x1900f2e8) at ../../third_party/WebKit/Source/WebKit/chromium/src/WebViewImpl.cpp:2058
#38 0x07db4d90 in content::RenderWidget::OnHandleInputEvent (this=0x6a998000, input_event=0x1900f2e8, is_keyboard_shortcut=true) at ../../content/renderer/render_widget.cc:732
#39 0x07dca53b in DispatchToMethod<content::RenderWidget, void (content::RenderWidget::*)(WebKit::WebInputEvent const*, bool), WebKit::WebInputEvent const*, bool> (obj=0x6a998000, method=not implemented: member type in c_val_print
) at tuple.h:553
#40 0x07dc2235 in ViewMsg_HandleInputEvent::Dispatch<content::RenderWidget, content::RenderWidget, void (content::RenderWidget::*)(WebKit::WebInputEvent const*, bool)> (msg=0x190279c8, obj=0x6a998000, sender=0x6a998000, func=not implemented: member type in c_val_print
) at view_messages.h:867
#41 0x07db3488 in content::RenderWidget::OnMessageReceived (this=0x6a998000, message=@0x190279c8) at ../../content/renderer/render_widget.cc:307
#42 0x07d50bae in content::RenderViewImpl::OnMessageReceived (this=0x6a998000, message=@0x190279c8) at ../../content/renderer/render_view_impl.cc:1136
#43 0x082c9133 in content::MessageRouter::RouteMessage (this=0x190a252c, msg=@0x190279c8) at ../../content/common/message_router.cc:49
#44 0x082c9085 in content::MessageRouter::OnMessageReceived (this=0x190a252c, msg=@0x190279c8) at ../../content/common/message_router.cc:41
#45 0x07f410b9 in content::ChildThread::OnMessageReceived (this=0x190a2514, msg=@0x190279c8) at ../../content/common/child_thread.cc:274
#46 0x03fec745 in IPC::ChannelProxy::Context::OnDispatchMessage (this=0x19098a40, message=@0x190279c8) at ../../ipc/ipc_channel_proxy.cc:261
#47 0x03ff5920 in base::internal::RunnableAdapter<void (IPC::ChannelProxy::Context::*)(IPC::Message const&)>::Run (this=0xc000b1d0, object=0x19098a40, a1=@0x190279c8) at bind_internal.h:190
#48 0x03ff580f in base::internal::InvokeHelper<false, void, base::internal::RunnableAdapter<void (IPC::ChannelProxy::Context::*)(IPC::Message const&)>, void ()(IPC::ChannelProxy::Context* const&, IPC::Message const&)>::MakeItSo (runnable=Unexpected type (16) encountered for integer constant.
) at bind_internal.h:899
#49 0x03ff5744 in base::internal::Invoker<2, base::internal::BindState<base::internal::RunnableAdapter<void (IPC::ChannelProxy::Context::*)(IPC::Message const&)>, void ()(IPC::ChannelProxy::Context*, IPC::Message const&), void ()(IPC::ChannelProxy::Context*, IPC::Message)>, void ()(IPC::ChannelProxy::Context*, IPC::Message const&)>::Run (base=0x190279b0) at bind_internal.h:1257
#50 0x026c51fb in base::Callback<void ()()>::Run (this=0xc000b464) at callback.h:396
#51 0x0438583a in base::MessageLoop::RunTask (this=0xc000d058, pending_task=@0xc000b450) at ../../base/message_loop.cc:474
#52 0x04385c92 in base::MessageLoop::DeferOrRunPendingTask (this=0xc000d058, pending_task=@0xc000b450) at ../../base/message_loop.cc:486
#53 0x04385e92 in base::MessageLoop::DoWork (this=0xc000d058) at ../../base/message_loop.cc:669
#54 0x042e280b in base::MessagePumpCFRunLoopBase::RunWork (this=0x6a16ef60) at ../../base/message_pump_mac.mm:252
#55 0x042e1fc2 in base::MessagePumpCFRunLoopBase::RunWorkSource (info=0x6a16ef60) at ../../base/message_pump_mac.mm:230
#56 0x9bc7e13f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#57 0x9bc7daf6 in __CFRunLoopDoSources0 ()
#58 0x9bca79c8 in __CFRunLoopRun ()
#59 0x9bca71dc in CFRunLoopRunSpecific ()
#60 0x9bca7088 in CFRunLoopRunInMode ()
#61 0x92f83543 in RunCurrentEventLoopInMode ()
#62 0x92f8a8ab in ReceiveNextEventCommon ()
#63 0x92f8a71a in BlockUntilNextEventMatchingListInMode ()
#64 0x99b31ee8 in _DPSNextEvent ()
#65 0x99b31752 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#66 0x99b2dac1 in -[NSApplication run] ()
#67 0x042e372e in base::MessagePumpNSApplication::DoRun (this=0x6a16ef60, delegate=0xc000d058) at ../../base/message_pump_mac.mm:576
#68 0x042e2578 in base::MessagePumpCFRunLoopBase::Run (this=0x6a16ef60, delegate=0xc000d058) at ../../base/message_pump_mac.mm:171
#69 0x043850a2 in base::MessageLoop::RunInternal (this=0xc000d058) at ../../base/message_loop.cc:431
#70 0x04384f5b in base::MessageLoop::RunHandler (this=0xc000d058) at ../../base/message_loop.cc:404
#71 0x043ea808 in base::RunLoop::Run (this=0xc000ccc0) at ../../base/run_loop.cc:45
#72 0x04384357 in base::MessageLoop::Run (this=0xc000d058) at ../../base/message_loop.cc:311
#73 0x07dd3a14 in content::RendererMain (parameters=@0xc000d348) at ../../content/renderer/renderer_main.cc:226
#74 0x086f4324 in content::RunNamedProcessTypeMain (process_type=@0xc000d368, main_function_params=@0xc000d348, delegate=0xc000d5a0) at ../../content/app/content_main_runner.cc:459
#75 0x086f5788 in content::ContentMainRunnerImpl::Run (this=0x6a16c080) at ../../content/app/content_main_runner.cc:764
#76 0x086f3457 in content::ContentMain (argc=7, argv=0xc000d620, delegate=0xc000d5a0) at ../../content/app/content_main.cc:35
#77 0x00017d2c in ChromeMain (argc=7, argv=0xc000d620) at ../../chrome/app/chrome_main.cc:32
#78 0x0000ff7b in main (argc=7, argv=0xc000d620) at ../../chrome/app/chrome_exe_main_mac.cc:16
(gdb) 

该错误似乎不在布局中(尽管看起来布局正在更新)。看起来问题在于更新拼写检查标记 - 就是WebCore::Editor::updateMarkersForWordsAffectedByEditing()这样。花时间试图找出要更新的内容的范围 - 它使用RuleBasedBreakIterator来确保范围开始和结束在“单词”边界上。边界搜索基本上一直加一个字,问:“这是一个完整的词吗?” 这是单词长度的 O(n^2) 但由于某种原因,对完整单词的测试一直失败,并且 n 是数千个......我用时间验证了行为确实是 O(n^2)表行数。WebCore::nextBoundary()这是(searchFunctionWebCore::nextWordPositionBoundary和是测试完整单词的搜索循环):

while (!it.atEnd()) {
    // Keep asking the iterator for chunks until the search function
    // returns an end value not equal to the length of the string passed to it.
    if (!inTextSecurityMode)
        string.append(it.characters(), it.length());
    else {
        // Treat bullets used in the text security mode as regular characters when looking for boundaries
        String iteratorString(it.characters(), it.length());
        iteratorString.fill('x');
        string.append(iteratorString.characters(), iteratorString.length());
    }
    next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext);
    if (next != string.size())
        break;
    it.advance();
}

无论您拥有多少省略号行,在 UTF-16 中,字符串的内容似乎都是“,\n...\n...\n...”。我不知道为什么WebCore::nextWordPositionBoundary()没有在换行符处检测到边界,我也不确定为什么它在<input>标签文本之外寻找。

我验证了 WebKit 夜间构建中存在该错误,并使用 WebKit 提交了一个错误

于 2013-04-05T20:42:02.620 回答
2

这是 WebKit 中的一个错误(主页/维基百科文章)。

我已经能够在以下操作系统/浏览器组合中重现此问题:

  • Windows 7 SP1 / Chrome 26.0.1410.43 m

  • OS X 10.8.3 / Safari 6.0.3 (8536.28.10)

  • Arch Linux 3.8.5-1 / Chromium 26.0.1410.43 (189671)(预编译)

  • Ubuntu 12.10 / Chromium 25.0.1364.160-0ubuntu0.12.10.1(预编译,可从 Ubuntu 软件中心获得)

因此,它本身无法通过 JavaScript 修复 - 您的解决方案是使用不同的显示方法如:

<tr><td style="border-bottom: dotted 1px #000; width: 5px; height: 10px;"></td></tr>

或者

<tr><td><span style="display: inline-block; border-bottom: dotted 1px #000; width: 10px;"></span></td></tr>

这是一个jsFiddle - 根据您的意图,其中一个可能会起作用。不幸的是,我尝试使用&#8230;and &#46;&#46;&#46;,但无济于事。


如前所述,这种行为在 Firefox 上看不到,也没有

  • Windows 7 SP1 / Internet Explorer 10

  • iPhone iOS 6.1.2 / Safari

  • iPad iOS 6.1.3 / Safari


对于那些不知道的人来说,仅供参考

WebKit: WebKit 是一种布局引擎软件,旨在允许网络浏览器呈现网页。(维基百科) WebKit 目前被 Chrome、Chromium 和 Safari 使用(截至撰写本文时,2013-04-05)。

Chromium: Chromium 是一个开源 Web 浏览器项目,Google Chrome 从中提取其源代码。浏览器共享大部分代码和功能,尽管存在一些细微差别。(维基百科)

于 2013-04-05T19:31:22.163 回答
1

在这部分代码中:

for (var i=0; i<peptides.data.length; i++)
  trs += peptides.row(peptides.data[i]);

如果您peptides.data以任何方式添加或更改长度,则可能会出现无限循环。这是因为peptides.data.length对循环的每次迭代都进行了评估。上面的代码中似乎没有发生这种情况,但您确实说它是一个删节版本。无论哪种方式,如果您不必peptides.data.length每次都进行评估,您的代码会更快一些,因此无论如何都值得更改:

for (var i=0, len = peptides.data.length; i<len; i++)
  ...

编辑-现在这个问题已经更新,我可以清楚地看到 OP 描述的问题;我也很想看看是否有比我聪明的人能弄清楚这里发生了什么。

于 2013-04-02T14:53:50.033 回答