gpt4 book ai didi

javascript - DOM 中相同元素的多次搜索

转载 作者:行者123 更新时间:2023-11-28 06:34:35 25 4
gpt4 key购买 nike

通过 jQuery 进行冒泡订阅存在性能问题。 IE9 和 IE11 表明 80% 的时间花在执行 querySelectorAll 上。 Analisis 显示了函数 $.event.dispatch(在 jQuery 1.8.1 中,在较新版本 (1.11.3) 中,此功能已移至 $.event.handlers),其中包含以下代码:

for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {

// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.disabled !== true || event.type !== "click" ) {
selMatch = {};
matches = [];
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;

if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = jQuery( sel, this ).index( cur ) >= 0;
}
if ( selMatch[ sel ] ) {
matches.push( handleObj );
}
}
if ( matches.length ) {
handlerQueue.push({ elem: cur, matches: matches });
}
}
}

注意以下几行:

// For each element from clicked and above
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
// Clear the search cache
selMatch = {};

// For each subscriber
for ( i = 0; i < delegateCount; i++ ) {
// Take the subscriber's selector
sel = handleObj.selector;

// If it's out of cache
if ( selMatch[ sel ] === undefined ) {
// Search for elements matching to the selector
// And remember if current element is among of found ones
selMatch[ sel ] = jQuery( sel, this ).index( cur ) >= 0;

由于订阅是在正文上进行的,因此每次此类搜索都会从整个文档中获取与选择器匹配的所有元素。并且重复此操作的次数与单击元素的深度相同。

据我了解,外循环是根据冒泡顺序保证处理程序的写入顺序。有一个缓存,但它仅在一个级别上工作,并且在使用同一选择器进行多个订阅的情况下有所帮助。

问题是为什么要这样实现缓存呢?为什么不保留 jQuery 集合并将 index 移动到下一个 if 条件?

<小时/>

但这还不是全部。我在1.11.3中查看了实际的实现。它还使用多个搜索,但是这行代码已更改。

在 1.8.1 中是:

selMatch[ sel ] = jQuery( sel, this ).index( cur ) >= 0;

在 1.11.3 中它变成了:

matches[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) >= 0 :
jQuery.find( sel, this, null, [ cur ] ).length;

在这种情况下进行同样的修改似乎并不合理。

<小时/>

所以,问题是:

  1. 什么原因可能导致此代码不是最佳的?
  2. 我应该如何解决性能问题?
<小时/>

以下代码片段显示了问题。

如果您打开浏览器控制台并单击点击我即可获得大量搜索!。您将看到以下行输出了 21 次:

qsa [id='sizcache041783330822363496'] section .smth
gbc smth-other

关于段[id='sizcache041783330822363496']有一个related question in Russian 。不久,这种形式简化了 id 中特殊字符的转义(如果它是原始的)。前段时间嘶嘶has updated this place ,但即使是实际的 jQuery 版本也不包含它。

$(function () {
$("body")
.on("click", "section .smth", function () { console.log("clicked", "section .smth") })
.on("click", ".smth-other", function () { console.log("clicked", ".smth-other") });

$("h1").text("Click me to get a lot of searches!");

var qsa = Element.prototype.querySelectorAll, gbc = Element.prototype.getElementsByClassName;
Element.prototype.querySelectorAll = function(s) { console.log('qsa', s); return qsa.apply(this, arguments) };
Element.prototype.getElementsByClassName = function(s) { console.log('gbc', s); return gbc.apply(this, arguments) };
});
body { counter-reset: lev 1; }
div { counter-increment: lev; }
h1, h2 { cursor: pointer; }
h1:hover, h2:hover { background: silver; }
h1:after { content: " (" counter(lev) ")"; }
<div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><h1>
Loading...
</h1></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>

<section>
<h2 class="smth">I'm smth and i'm waiting for a click</h2>
</section>

<section>
<h2 class="smth-other">I'm smth other and i'm waiting for a click</h2>
</section>

<script src="//code.jquery.com/jquery-1.8.1.js"></script>

<小时/>

下一个片段显示了 jQuery 1.8.1 dispatch 函数的完整代码(片段用于制作可折叠扰流板,不是用于运行代码):

dispatch: function( event ) {

// Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );

var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
delegateCount = handlers.delegateCount,
args = [].slice.call( arguments ),
run_all = !event.exclusive && !event.namespace,
special = jQuery.event.special[ event.type ] || {},
handlerQueue = [];

// Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
event.delegateTarget = this;

// Call the preDispatch hook for the mapped type, and let it bail if desired
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
return;
}

// Determine handlers that should run if there are delegated events
// Avoid non-left-click bubbling in Firefox (#3861)
if ( delegateCount && !(event.button && event.type === "click") ) {

for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {

// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.disabled !== true || event.type !== "click" ) {
selMatch = {};
matches = [];
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;

if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = jQuery( sel, this ).index( cur ) >= 0;
}
if ( selMatch[ sel ] ) {
matches.push( handleObj );
}
}
if ( matches.length ) {
handlerQueue.push({ elem: cur, matches: matches });
}
}
}
}

// Add the remaining (directly-bound) handlers
if ( handlers.length > delegateCount ) {
handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
}

// Run delegates first; they may want to stop propagation beneath us
for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
matched = handlerQueue[ i ];
event.currentTarget = matched.elem;

for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
handleObj = matched.matches[ j ];

// Triggered event must either 1) be non-exclusive and have no namespace, or
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {

event.data = handleObj.data;
event.handleObj = handleObj;

ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
.apply( matched.elem, args );

if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}

// Call the postDispatch hook for the mapped type
if ( special.postDispatch ) {
special.postDispatch.call( this, event );
}

return event.result;
},

PS:Same question in Russian.

最佳答案

我用缓存提升了线路:

if ( delegateCount && !(event.button && event.type === "click") ) {
selMatch = {};

将对 index 的调用从缓存移至下一个条件:

if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = jQuery( sel, this );
}
if ( selMatch[ sel ].index( cur ) >= 0 ) {
matches.push( handleObj );
}

关于javascript - DOM 中相同元素的多次搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34402369/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com