11

在 DevTools 中使用“配置文件”调试我的应用程序时,我发现“分离的 DOM 树”正在累积。这些分离的节点具有主要由函数组成的保留树checkContext(来自jQuery内部的嘶嘶声- v1.10.1)。

堆快照

我不确定如何进行此操作。这个结果什么意思?

4

2 回答 2

6

Sizzle 将编译的选择器存储在选择器缓存中,默认情况下最多存储 50 个条目。您可以$.expr.cacheLength = 1在进行任何选择之前通过设置进行试验,看看它们是否会消失。

这是文档https://github.com/jquery/sizzle/wiki/Sizzle-Documentation#-internal-api。似乎是内部的,所以不要依赖它或实际生产代码中的任何东西。

于 2013-06-24T15:33:35.077 回答
4

这实际上是一个错误,Sizzle 没有理由需要挂在上下文节点上,它只是这样做是因为它在设置临时变量后没有清理。我为它提交了一个问题,修复了它,运行了所有的 Sizzle 测试,并做了一个拉取请求。

如果你想修补现有的 jQuery 或 Sizzle 副本:

  1. 打开你的 jQuery 或 Sizzle 文件

  2. 搜索matcherFromTokens功能

  3. 在其中找到此代码(靠近顶部):

    matchers = [ function( elem, context, xml ) {
        return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
            (checkContext = context).nodeType ?
                matchContext( elem, context, xml ) :
                matchAnyContext( elem, context, xml ) );
    } ];
    
  4. 将 更改return为,然后在匿名函数的末尾var rv =添加checkContext = undefined;然后,例如:return rv;

    matchers = [ function( elem, context, xml ) {
        var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
            (checkContext = context).nodeType ?
                matchContext( elem, context, xml ) :
                matchAnyContext( elem, context, xml ) );
        // Release the context node (issue #299)
        checkContext = null;
        return ret;
    } ];
    

注意:该代码分配nullcheckContext因为显然这是他们的风格。如果是我,我会分配undefined

如果在拉取请求/合并过程中提出的修复有任何问题,我会更新答案。

最好继续让 Sizzle 缓存选择器,因为 jQuery 使用带有事件委托的已编译选择器的东西,而且你真的不希望它每次发生相关事件时都必须重新解析和重建匹配器函数,以便它可以确定元素是否匹配它。


不幸的是,这不是 jQuery 在已编译选择器中保留元素的唯一位置。它所做的每个地方都可能是一个可以使用修复的错误。我只有时间去追踪另一个,我也报告并修复了(等待拉取请求被登陆):

如果你搜索“Potentially complex pseudos”,你会发现这个:not伪选择器:

pseudos: {
    // Potentially complex pseudos
    "not": markFunction(function( selector ) {
        // Trim the selector passed to compile
        // to avoid treating leading and trailing
        // spaces as combinators
        var input = [],
            results = [],
            matcher = compile( selector.replace( rtrim, "$1" ) );

        return matcher[ expando ] ?
            markFunction(function( seed, matches, context, xml ) {
                var elem,
                    unmatched = matcher( seed, null, xml, [] ),
                    i = seed.length;

                // Match elements unmatched by `matcher`
                while ( i-- ) {
                    if ( (elem = unmatched[i]) ) {
                        seed[i] = !(matches[i] = elem);
                    }
                }
            }) :
            function( elem, context, xml ) {
                input[0] = elem;
                matcher( input, null, xml, results );
                return !results.pop();
            };
    }),

:问题出在条件运算符中的函数中:

function( elem, context, xml ) {
    input[0] = elem;
    matcher( input, null, xml, results );
    return !results.pop();
};

请注意,它永远不会清除input[0]. 这是修复:

function( elem, context, xml ) {
    input[0] = elem;
    matcher( input, null, xml, results );
    // Don't keep the element (issue #299)
    input[0] = null;
    return !results.pop();
};

这就是我目前有时间追查的所有内容。

于 2014-12-02T19:36:58.200 回答