Rumah  >  Artikel  >  hujung hadapan web  >  Perbincangan ringkas tentang 'prinsip kompilasi' Sizzle _Lain-lain

Perbincangan ringkas tentang 'prinsip kompilasi' Sizzle _Lain-lain

WBOY
WBOYasal
2016-05-16 16:04:20806semak imbas

Sizzle ialah enjin pemilih DOM yang ditulis oleh pengarang jQuery John Resig Kepantasannya dikenali sebagai yang pertama dalam industri. Sebagai enjin pemilih baharu yang bebas, ia muncul selepas versi jQuery 1.3 dan diterima pakai sebagai projek sumber terbuka oleh John Resig. Sizzle ialah bahagian bebas dan tidak bergantung pada mana-mana perpustakaan Jika anda tidak mahu menggunakan jQuery, anda boleh menggunakan Sizzle, atau ia boleh digunakan dalam rangka kerja lain seperti Mool, Dojo, YUI, dll.

Beberapa hari yang lalu saya sedang menyediakan PPT perkongsian tentang jQuery, dan saya bertanya kepada rakan sekerja saya jika ada perkara lain yang mereka ingin tahu tentang jQuery selain cara menggunakannya Seseorang menyebut bahawa mereka ingin mengetahui cara pemilihnya dilaksanakan , dan beberapa Orang menyebut bagaimana kelajuan pertanyaan jQuery dibandingkan dengan rangka kerja lain. Mengenai kelajuan, anda boleh memuat turun contoh ujian dari laman web rasmi sizzle Kelajuan memang sangat menguntungkan. Tetapi mengapa ia mempunyai kelajuan larian yang cekap mempunyai kaitan dengan prinsip pelaksanaan yang saya ingin bincangkan di sini.

Sebelum anda memahami Sizzle, anda mesti memahami terlebih dahulu apakah pemilihnya. Berikut ialah contoh mudah Pelajar yang biasa dengan jQuery juga mesti biasa dengan format pemilih ini:

Salin kod Kod adalah seperti berikut:

tag #id .class , a:first

Ia menapis secara mendalam dari kiri ke kanan untuk mencari elemen DOM yang sepadan. Tidak sukar untuk melaksanakan pernyataan pertanyaan ini sendiri. Walau bagaimanapun, penyataan pertanyaan hanya mempunyai peraturan asas dan tiada nombor tetap dan susunan pemilih Bagaimana kita boleh menyesuaikan diri dengan susunan dan gabungan sewenang-wenang ini apabila kita menulis kod kita sendiri? Sizzle boleh mencapai analisis biasa dan pelaksanaan pelbagai situasi.

Kod sumber Sizzle sememangnya rumit dan sukar untuk memahami ideanya. Mari kita ketepikan lapisan luar pembungkusan dan lihat terus pada tiga kaedah yang saya fikir secara peribadi adalah teras keseluruhan pelaksanaan:

Kaedah teras pertama. Terdapat fungsi tokenize dalam baris 1052 kod sumber:

Salin kod Kod adalah seperti berikut:

tokenize fungsi(pemilih, parseSahaja) { }

Parameter kedua parseOnly adalah palsu, yang bermaksud bahawa hanya operasi bersiri token dilakukan dan tiada hasil dikembalikan Dalam kes ini, hasil bersiri akan dicache untuk digunakan kemudian. Pemilih ialah pernyataan pertanyaan.

Selepas diproses oleh fungsi ini, contohnya, jika selector="#idtag.class, a:first" dihantar, anda boleh mendapatkan hasil yang serupa dengan format berikut:

[
[
{matches:" id ",type:"ID"},
{matches:" tag ",type:"TAG"},
{matches:" class ",type:"CLASS"},
...
],
[
    {matches:" a",type:"TAG"},
    ...
],
[…],
…
]


Melihat nama fungsi tokenize dan fungsinya, saya boleh dengan mudah memikirkan perkataan "prinsip kompilasi". Ia agak seperti analisis leksikal di sini, tetapi analisis leksikal ini lebih mudah daripada analisis leksikal yang dilakukan apabila program disusun.

Kaedah tokenize akan melakukan "pembahagian perkataan" berdasarkan ungkapan biasa koma, ruang dan pemilih relasi dalam pemilih, dan mendapatkan tatasusunan dua dimensi (sila benarkan saya menggunakan nama yang tidak tepat ini), di mana yang pertama tatasusunan -dimensi Mereka dipisahkan dengan koma dan dipanggil kumpulan dalam kod sumber.

Mari kita lihat semula kod sumber Terdapat definisi Expr = Sizzle.selectors = {} bermula dari baris 405. Terdapat definisi penapis pada baris 567. Di sini kita boleh mencari jenis penapisan asas: "ID. ", "TAG", "CLASS", "ATTR", "KANAK-KANAK", "PSEUDO", ini ialah jenis yang akhirnya dikelaskan mengikut tokenize.

Selepas "pembahagian perkataan" selesai, masih lihat Expr= Sizzle.selectors = {} yang ditakrifkan dalam baris 405. Semua pemilih yang kita kenali boleh didapati di sini, dan setiap pemilih sepadan dengan definisi kaedah. Pada ketika ini, anda harus memikirkan sama ada Sizzle benar-benar melaksanakan "pembahagian perkataan" pada pemilih, memecahkannya dan kemudian mencari kaedah yang sepadan daripada Expr untuk melaksanakan pertanyaan atau operasi penapisan tertentu?

Jawapannya pada asasnya ya. Tetapi Sizzle mempunyai pendekatan yang lebih spesifik dan bijak. Mari lihat kaedah kedua yang saya rasa sangat teras:

Terdapat fungsi matcherFromTokens dalam baris 1293 kod sumber:

Salin kod Kod adalah seperti berikut:
fungsi matcherFromTokens(token) { }

Parameter yang diluluskan diperoleh daripada kaedah tokenize. Matcher boleh difahami sebagai "program padanan". Secara literal, fungsi fungsi ini adalah untuk menjana program padanan melalui token. Sebenarnya ia adalah. Disebabkan oleh had ruang, artikel ini hanya akan berkongsi beberapa prinsip pelaksanaan Sizzle yang saya fahami dan tidak akan menyiarkan kod sumber. Apabila saya mempunyai masa kemudian, saya boleh menyusun artikel analisis kod sumber yang lebih terperinci.

Kaedah matcherFromTokens mengesahkan andaian sebelumnya Ia bertindak sebagai sambungan dan pautan antara "segmentasi perkataan" pemilih dan kaedah pemadanan yang ditakrifkan dalam Expr. Perkara yang bijak tentang Sizzle ialah ia tidak secara langsung memadankan hasil "segmentasi perkataan" yang diperolehi dengan kaedah dalam Expr satu demi satu dan melaksanakannya satu demi satu Sebaliknya, ia mula-mula menggabungkan kaedah pemadanan yang besar mengikut peraturan dan melaksanakannya dalam langkah terakhir. Tetapi cara untuk melaksanakannya selepas gabungan bergantung pada kaedah kunci ketiga:

Terdapat kaedah superMatcher pada baris 1350 kod sumber:

Salin kod Kod adalah seperti berikut:

superMatcher = fungsi( benih, konteks, xml, hasil, kembangkanKonteks ) { }

Kaedah ini bukan kaedah yang ditakrifkan secara langsung, tetapi dikembalikan melalui kaedah matcherFromGroupMatchers(elementMatchers, setMatchers) pada baris 1345, tetapi ia memainkan peranan penting dalam pelaksanaan akhir.

Kaedah superMatcher akan menentukan julat pertanyaan permulaan berdasarkan benih parameter, expandContext dan konteks Ia mungkin pertanyaan dan tapis terus daripada benih, atau ia mungkin dalam konteks atau julat nod induk konteks. Jika ia tidak bermula dari seed, maka ia akan mula-mula melaksanakan kod Expr.find["TAG"]( "*", expandContext && context.parentNode || context ) dan tunggu koleksi elem (array). Kemudian lakukan traversal elem, dan gunakan kaedah pemadan yang telah dijana untuk memadankan elemen satu demi satu Jika hasilnya benar, elemen akan ditimbun terus ke dalam set hasil yang dikembalikan.

Baiklah, memandangkan hasil asal kaedah pemadan di sini adalah semua nilai bool, mari kita kembali ke baris 405 dan lihat kaedah yang disertakan dalam penapis dalam Expr. Termasuk lebih banyak kaedah pseudo-class yang sepadan dengan PSEUDO (pseudo-class) adalah sama. Nampaknya agak subversif daripada idea asal saya Ternyata ia tidak menyemak lapisan demi lapisan, tetapi ia agak seperti kembali dan ke atas untuk melakukan pemadanan dan penapisan. Dalam Expr, hanya cari dan praFilter set pulangan.

Walaupun saya masih mempunyai keraguan tentang mengapa ia menggunakan kaedah padanan dan penapisan satu demi satu untuk mendapatkan set hasil, saya fikir "prinsip kompilasi" paling asas Sizzle sepatutnya dijelaskan dengan jelas.

Tetapi kami tidak boleh meninggalkan sebarang keraguan, mari teruskan. Malah, artikel ini sendiri seolah-olah ditulis ke belakang. Pelajar yang berminat untuk melihat kod sumber tidak akan melihat tiga kaedah utama ini pada permulaan. Malah, Sizzle juga melakukan beberapa siri tugasan lain sebelum memasuki ketiga-tiga kaedah ini.

Pintu masuk sebenar ke Sizzle boleh dikatakan berada di baris 220 kod sumber:

Salin kod Kod adalah seperti berikut:

fungsi Sizzle( pemilih, konteks, hasil, benih ){ }

Perenggan pertama kaedah ini agak mudah difahami Jika pemilih boleh dipadankan dengan pemilih ID tunggal (#id), maka elemen itu boleh didapati secara langsung menggunakan kaedah context.getElementById(m) berdasarkan pada. id. Jika pemilih boleh dipadankan dengan pemilih TAG tunggal, mula-mula gunakan kaedah context.getElementsByTagName(selector) untuk mencari elemen yang berkaitan. Jika penyemak imbas semasa hanya menggunakan getElementsByClassName asli dan pemilih yang dipadankan ialah pemilih CLASS tunggal, kaedah context.getElementsByClassName(m) juga akan digunakan untuk mencari elemen yang berkaitan. Ketiga-tiga kaedah ini adalah semua kaedah asli yang disokong oleh penyemak imbas, dan kecekapan pelaksanaannya pastinya yang tertinggi.

Jika kaedah paling asas tidak tersedia, anda akan memasukkan kaedah pilih. Baris 1480 kod sumber mempunyai definisinya:

Salin kod Kod adalah seperti berikut:

fungsi pilih( pemilih, konteks, hasil, benih, xml ) { }

Dalam kaedah pilih, operasi "segmentasi perkataan" yang kami nyatakan sebelum ini akan terlebih dahulu dilakukan pada pemilih. Walau bagaimanapun, selepas operasi ini, kami tidak mula memasang kaedah pemadanan secara langsung, tetapi melakukan beberapa operasi cari dahulu. Operasi cari di sini boleh sepadan dengan carian dalam Expr. Ia menjalankan operasi pertanyaan dan mengembalikan set hasil.

Boleh difahamkan pilih menggunakan pemilih yang diperolehi oleh "word segmentation" untuk mengetahui terlebih dahulu set hasil yang boleh dicari menggunakan kaedah find mengikut jenisnya. Apabila melakukan operasi cari, set hasil dikecilkan dari kiri ke kanan mengikut susunan pemilih. Jika selepas traversal, semua pemilih dalam pemilih boleh melakukan operasi cari, hasilnya akan dikembalikan terus. Jika tidak, ia akan memasuki "penyusunan" dan proses penapisan yang diterangkan sebelum ini.

Pada ketika ini, anda juga boleh datang dan memahami secara asas aliran kerja Sizzle. Soalan yang ditinggalkan di atas sebenarnya bukan lagi soalan pada ketika ini, kerana apabila melakukan penapisan padanan terbalik, julat cariannya sudah menjadi set terkecil yang telah ditapis lapisan demi lapisan. Kaedah penapisan padanan terbalik sebenarnya merupakan pilihan yang cekap untuk pemilih yang sepadan dengannya, seperti kelas pseudo.

Mari kita ringkaskan secara ringkas sebab Sizzle sangat cekap.

Pertama sekali, Dari segi aliran pemprosesan, ia sentiasa menggunakan kaedah asli yang paling berkesan untuk pemprosesan dahulu. Apa yang telah diperkenalkan sebelum ini hanyalah kaedah pelaksanaan pemilih Sizzle sendiri Apabila Sizzle sebenarnya dilaksanakan, ia akan terlebih dahulu menentukan sama ada penyemak imbas semasa menyokong kaedah asli querySelectorAll (baris kod sumber 1545). Jika disokong, kaedah ini akan digunakan terlebih dahulu Kaedah yang disokong secara asli oleh penyemak imbas pasti lebih cekap daripada kaedah yang ditulis oleh js sendiri Menggunakannya juga boleh memastikan kecekapan kerja Sizzle yang lebih tinggi. (Anda boleh menyemak lebih banyak maklumat dalam talian tentang querySelectorAll). Apabila kaedah querySelectorAll tidak disokong, Sizzle juga memberi keutamaan untuk menentukan sama ada ia boleh terus menggunakan getElementById, getElementsByTag, getElementsByClassName dan kaedah lain untuk menyelesaikan masalah.

Kedua, dalam situasi yang agak kompleks, Sizzle sentiasa memilih untuk mula-mula menggunakan kaedah asli untuk membuat pertanyaan dan memilih sebanyak mungkin untuk mengecilkan julat pemilihan, dan kemudian menggunakan "prinsip kompilasi" yang diperkenalkan sebelum ini untuk menyempitkan julat pemilihan Elemen dipadankan satu demi satu dan ditapis. Aliran kerja ke dalam langkah "kompilasi" agak rumit, dan kecekapan pasti akan lebih rendah sedikit daripada kaedah sebelumnya, tetapi Sizzle cuba menggunakan kaedah ini sesedikit mungkin, dan pada masa yang sama, ia juga cuba untuk jadikan set hasil diproses dengan kaedah ini sekecil dan semudah mungkin , untuk mendapatkan kecekapan yang lebih tinggi.

Sekali lagi , walaupun selepas memasuki proses "kompilasi" ini, Sizzle juga melaksanakan mekanisme caching yang kami abaikan buat sementara waktu dan tidak perkenalkan untuk menjelaskan proses itu terlebih dahulu. Baris 1535 kod sumber ialah apa yang kita panggil entri "kompilasi", yang bermaksud ia memanggil kaedah teras ketiga superMatcher. Jejak masuk dan lihat baris 1466. Kaedah penyusunan cache fungsi pemadanan yang dijana berdasarkan pemilih. Bukan itu sahaja, tetapi lihat kaedah tokenize pada baris 1052. Ia sebenarnya cache hasil segmentasi perkataan berdasarkan pemilih. Dalam erti kata lain, selepas kami melaksanakan kaedah Sizzle (pemilih) sekali, dan memanggil kaedah Sizzle (pemilih) secara langsung pada kali seterusnya, proses "kompilasi" yang paling memakan prestasi di dalamnya tidak akan menggunakan terlalu banyak prestasi, dan cache sebelumnya akan akan diambil secara langsung. Saya berpendapat bahawa salah satu faedah terbesar dari apa yang dipanggil "penyusun" mungkin adalah ia memudahkan caching Apa yang dipanggil "kompilasi" di sini juga boleh difahami sebagai menjana fungsi praproses dan menyimpannya untuk kegunaan kemudian.

Pada ketika ini, saya berharap pada asasnya saya dapat menjawab soalan pelajar yang sebelum ini mengambil berat tentang prinsip pelaksanaan dan kecekapan pelaksanaan pemilih. Di samping itu, kesimpulan analisis artikel ini diperoleh daripada kod sumber versi terkini Sizzle Nombor baris kod yang disebut dalam artikel adalah tertakluk kepada kod sumber versi ini, yang boleh dimuat turun daripada http: //sizzlejs.com/. Masa adalah singkat, jadi harap maaf jika terdapat sebarang ketidaksempurnaan dalam analisis Pelajar yang masih mempunyai soalan dialu-alukan untuk terus berkomunikasi di luar talian.

Di atas adalah keseluruhan kandungan artikel ini, saya harap anda semua menyukainya.

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn