ペピーについてのメモの後
、私はほとんど喜んでいた-それ、それは幸せです。 最後に、CSSセレクターエンジンが登場しました。これは
jQueryと同じことをするだけで、より高速です。 はるかに高速。
喜ぶのはそう長くはありませんでした。コードを調べるとすぐに、私は少し恐ろしくなりました。それは、並外れたパフォーマンスに関する私の考えに対応していませんでした。 まったく一貫していません。 より正確には、少し満足していますが、最後までではありません。 したがって、問題はすぐに発生しました。高速であればどうでしょうか。
DOMを操作するための基本的な機能を提供するCSSセレクターのクイックミニコアを作成することが不可能なのはなぜですか(まあ、非常に基本的なもの-要素の選択など)。 そして、最も重要なことは、ネイティブコールよりも遅く(理想的には、さらに速く)動作しないことです。
パフォーマンスの基本
まあ、考えてやった。 2つの眠れない後
日数 CSS1セレクターで要素を選択するための簡単なエンジンの概要を説明した夜(XPATHは1桁遅いテクノロジーとして同時に廃止され、
jsFormsがブラウザーの組み込みDOMメソッドよりもわずかに遅く動作する理由が認識されました)。
第二に、このようなコードはサンプルもキャッシュする必要があります(DOM呼び出しは高価であり、すべての通常のJavaScriptプログラマーがすでにサンプルをキャッシュしているため、タスクを簡素化し、パフォーマンスを向上させます)。
第三に、プロジェクト
でのCSSセレクターの使用に関する統計情報があります。これは、最も高速に実行する必要のある基本操作のセットがあることを意味します(より一般的なパフォーマンスを損なう場合もあります)。
第4に、ライブラリは要素自体を返さなければならないため、ラッパーはすべてのラッパーとビルドメソッドを「結び付ける」ことができます。 すべてのリソースを消費するラッパー。 指定された要素のページでHTMLを200回変更する必要がある場合、それらは必要ありません。 実行された操作の妥当性に関する十分な確認とブラウザーからの確認。
第5に、もちろん、ライブラリは最速のものすべてに依存する必要があります。
高速イテレータ 、
高速ルックアップ 、匿名関数、ネストされた呼び出しの最小数などです。
コード
コード自体はより良い説明として提供します(
YASSテストページでも入手可能です)。これはそれほど多くないためです(これはミニコアであるため、逆光で申し訳ありませんが、非常に読みやすくなりませんでした)。
/* */
( function (){
/* , window. _
-- $ */
var _ = function () {
/* document */
var doc = document ,
/* */
selector = arguments[0],
/* */
nocache = arguments[1];
/* , */
if (_.cache[selector] && !nocache) {
return _.cache[selector];
} else {
/* querySelectorAll, Safari */
if (doc[ 'querySelectorAll' ]) {
_.nodes = doc[ 'querySelectorAll' ](selector);
} else {
switch (selector) {
/* . , body */
case 'body' :
_.nodes = doc.body;
break ;
/* head */
case 'head' :
_.nodes = doc[ 'getElementsByTagName' ]( 'head' )[0];
break ;
case 'a' :
_.nodes = doc.links ? doc.links : doc[ 'getElementsByTagName' ]( 'a' );
break ;
case 'img' :
_.nodes = doc.images ? doc.images : doc[ 'getElementsByTagName' ]( 'img' );
break ;
/* , */
default :
/* , */
var groups = selector.replace(/, +/g, "," ).split( "," ),
groups_length = groups.length - 1;
j = -1;
/* while, for -- */
while (j++ < groups_length) {
/* , -id- */
var singles = groups[j].split( ' ' ),
singles_length = singles.length - 1,
i = -1,
level = 0;
/* */
_.nodes = doc;
while (i++ < singles_length) {
/*
(-id-), :
webo.in/articles/habrahabr/40-search-not-replace
*/
singles[i].replace(/([^\.#]+)?(#([^\.#]+))?(\.([^\.#]+))?/, function (a, tag, b, id, c, klass) {
/* , id ( ) */
if (tag == '' && klass == '' && !level) {
_.nodes = doc[ /*@cc_on !@*/ 0 ? 'all' : 'getElementById' ](id);
} else {
/* , */
if (klass == '' && id == '' && !level) {
_.nodes = doc[ 'getElementsByTagName' ](tag);
/* , id */
} else {
/* , */
var newNodes = {},
/* */
nodes_length = _.nodes.length,
J = -1,
/* , */
idx = 0;
/* 1 ,
*/
if (!nodes_length) {
_.nodes = [_.nodes[0]?_.nodes[0]:_.nodes];
nodes_length = 1;
}
/* while, for-in for */
while (J++ < nodes_length) {
var node = _.nodes[J];
if (node) {
/* */
var childs = node[ 'getElementsByTagName' ](tag ? tag : '*' ),
childs_length = childs.length,
h = -1;
while (h++ < childs_length) {
var child = childs[h];
/* id */
if (child && (!id || (id && child.id == id)) && (!klass || (klass && child.className.match(klass)))) {
/* */
newNodes[idx++] = child;
}
}
}
}
/* */
_.nodes = newNodes;
_.nodes.length = idx - 1;
}
}
/* "" "" --
"" id */
level++;
});
/* --
, */
if (groups_length) {
var nodes_length = _.nodes.length,
K = -1,
idx = _.sets ? _.sets.length : 0;
_.sets = _.sets ? _.sets : {};
while (K++ < nodes_length) {
_.sets[idx++] = _.nodes[K];
}
_.sets.length = idx;
/* */
} else {
_.sets = _.nodes;
}
}
}
break ;
}
}
/* , . ,
. */
_.sets = _.sets ? _.sets : _.nodes;
/* , , */
_.cache[selector] = _.sets.length>1||_.sets.nodeName ? _.sets : _.sets[0];
/* DOM
-- , IE */
_.sets = _.nodes = null ;
/* */
return _.cache[selector];
}
};
/* */
_.nodes = null ;
/* , , */
_.sets = null ;
/* */
_.cache = {};
/* : window._ */
window._ = _;
})();
呼び出し例
すべてがとてつもなく単純です:
_('p')
-ページ上のすべての段落を返します
_('p a')
-またはその中のすべてのリンク
_('p a.blog')
-または
blog
クラスのすべてのリンク
など 完全なCSS1ガンマ。
別の自転車?
たぶん、この状況は些細なことのように思えるかもしれませんが、私は個人的には次のように状況のさらなる発展を見るでしょう。 または、コードを教育目的に使用して、ブラウザがCSSセレクター(組み込みエンジン内)を認識するために使用する有限状態マシンのロジックを理解し、些細な状況またはそうでない状況をモデル化することができます。
または、このコードを完成させて、高性能ライブラリのベースに含めることができます。これにより、すでにそのメソッドが完成します。 ご覧のとおり、コードは非常に拡張性が高く、モジュール化されています。 彼が必要なのはブラウザだけです:)
結論として
近い将来、JavaScriptのさまざまなメソッドとアプローチのパフォーマンスに関する一連の研究を行う予定です。結局のところ、それは(Web)アプリケーションの未来です。 CSSセレクターは、これまで(そして長い間、IEでquerySelectorAllが実装されるまで)、アプリケーションを構築する「クジラ」の1つです。 そして、このクジラがより速くなると、他のすべてがより速く動作します。
YASSの現在のバージョン(yeasss!:と読みます)は0.1です。 開発します。 現在のコードサイズ:約6 Kb(すべてのコメント付き)、1,5-最小化バージョンおよび
650バイト -アーカイブ。 考えてみてください:CSS1セレクターを使用してページ上の任意の要素を選択するための650バイトの縮小コード。 そして、直接的な方法を使用するよりもゆっくりと選択すること(差は-10 ... +キャッシュによるネイティブメソッドの30%です)。
テストが来ています。 これまでのところ、現在の実装は
Peppyよりも
1.5〜2倍高速で、すでにすべてのユーザーを追い越しています。
PS一般に、予想どおり、yassは現在のライブラリよりもはるかに高速です。 テストのみが失敗します:)
テスト環境に感謝します。
ここで結果を
見ることができ
ます。