2011-01-15 39 views
7

Tôi đã tự hỏi ngày khác khi gõ các bộ chọn trong jQuery, nó sẽ tạo ra sự khác biệt về hiệu suất nếu bạn chỉ định các bộ chọn của bạn rất cụ thể hoặc rất lỏng lẻo.Bộ chọn tối ưu hóa jQuery

Ví dụ

$('$myId .someElement') 

Hoặc

$('table#myId > tbody > tr > td > div.someElement'); 

có tùy chọn thứ 2 có rất nhiều nhanh hơn hay phần chênh lệch sẽ là neglectable, nói khi làm .each() nếu bạn cần phải tìm các yếu tố tương tự hơn và hơn .

Trả lời

4

tôi sẽ đi cho:

$('.someElement', '#myId') 

Kể từ getElementById là hoạt động chọn nhanh nhất, bạn đang đầu lọc nội dung của bạn và sau đó tìm kiếm các lớp. Ngoài ra, bộ chọn càng ít lựa chọn càng nhanh (phụ thuộc vào việc sử dụng hậu duệ hoặc con chọn lọc số - kiểm tra nhận xét!). Test dựa trên trường hợp kiểm tra @Felix.

Chỉnh sửa: để nâng cao câu trả lời này. Dựa trên jQuery documentation:

Theo mặc định, chọn lọc dùng thực hiện tìm kiếm của họ trong DOM bắt đầu từ gốc tài liệu. Tuy nhiên, một ngữ cảnh thay thế có thể được cung cấp cho tìm kiếm bằng cách sử dụng tham số thứ hai tùy chọn cho hàm $().

Vì vậy, khi bạn cung cấp một tham số thứ hai (một ngữ cảnh), jQuery sẽ tìm kiếm cho rằng yếu tố đầu tiên và sau đó tìm kiếm bên trong nó, vì vậy nó sẽ được dịch từ:

$('.someElement', '#myId') 

Để:

$('#myId').find('.someElement') 

Bây giờ lừa được, cố gắng tìm container gần nhất của nguyên tố của bạn mà thực sự giữ một ID và đặt nó như bối cảnh, vì chọn ID là nhanh nhất. Bây giờ bạn có thể nói, tại sao không sau đó sử dụng thứ hai đã được dịch một, bởi tôi sẽ không thực sự quan tâm rằng có rất nhiều kể từ khi đầu tiên là sạch và nó không có nhiều chậm:

    $('.someElement', '#myId')     $('#myId').find('.someElement') 
Chrome 8.0.552    36,527          37,400 
Firefox 3.6.13    17,632          19,155 
+0

Không mong đợi kết quả này, điều này chắc chắn là câu trả lời đúng! Cảm ơn – Michael

+0

@Michael: Bạn được chào đón, và xin vui lòng không trực tiếp * đánh dấu * nút trả lời khi câu hỏi của bạn đang hoạt động, đặc biệt là khi có những người như @Felix tham gia ;-) – ifaour

+0

: D Tôi lấy điều này như một lời khen :) Btw. kết quả thú vị. Tôi nghĩ '$ ('# myId .someElement')' sẽ nhanh hơn trong mọi trường hợp, vì nó có thể được dịch trực tiếp sang 'querySelectorAll ('$ myId .someElement')', nhưng có vẻ như '$ ('# myId') .find ('. someElement') 'nhanh hơn rất nhiều. Wow. –

5

Cập nhật 2:

Tổng hợp một số ý kiến ​​khác ở đây. Câu trả lời là tùy thuộc vào.

Công cụ chọn của jQuery Sizzle đánh giá bộ chọn giống như cách CSS thực hiện: from right to left. Vì vậy, nói chung nó là tốt hơn để được rất cụ thể về phía bên phải và ít cụ thể ở phía bên trái.

Nhưng nó cũng phụ thuộc vào cấu trúc của HTML và cách phân tán các phần tử mà bạn muốn tìm.

Vì vậy, nếu bạn có

      a 
         | 
         ... 
         | 
         b 
       ----------------- 
       |    | 
d d d c c c c c c c c c c c c c c c c c c c 

sau đó là cụ thể hơn là nhanh hơn $('a b > c'), bởi vì bạn đang làm giảm các yếu tố thiết lập sớm với b > c và không cần phải kiểm tra a thừa kế cho mỗi c.

Trong khi đó nếu bạn có

      a 
         | 
         ... 
         | 
         b 
       ----------------- 
       |    | 
e e e e e e e e d d c c c c c c e e e e e e 

sau đó $('a c') sẽ nhanh hơn, kể từ khi chọn đơn giản hơn và thử nghiệm c cho là một đứa trẻ của b là không cần thiết trong trường hợp này (tất nhiên bạn có thể thậm chí làm $('c')).


Original câu trả lời:

Bất kể mà một trong số họ là nhanh hơn, nếu bạn phải truy cập vào một yếu tố hơn và hơn nữa, cửa hàng một tham chiếu đến nó:

var $element = $('#myId .someElement'); 

$('some other selector').each(function() { 
    // access $element here 
}); 

The first selector seems to be a bit faster (trong Chrome 8).

Trong các trình duyệt mới hơn (hỗ trợ querySelectorAll), sự khác biệt có thể không lớn bằng các trình duyệt không hỗ trợ.

Cập nhật:

Tôi nghĩ rằng nó chủ yếu phụ thuộc vào bao nhiêu phương pháp tích hợp jQuery có thể sử dụng.Vì vậy, giả sử querySelector* không có sẵn, chọn đầu tiên có thể được dịch sang

document.getElementById('myId')[0].getElementsByClassName('someElement') 

Đối với bộ chọn thứ hai, jQuery sẽ phải kiểm tra bổ sung cho dù một yếu tố thực sự là một đứa trẻ hay không. I E. có một số xử lý hơn có liên quan.

+0

Đừng nghĩ đây là câu trả lời cho câu hỏi. – PeeHaa

+0

@PeeHaa: Vâng, tôi thấy hai phần trong câu hỏi này: 1) Bộ chọn nào nhanh hơn? 2) Để sử dụng nó trong một vòng lặp 'mỗi'. Câu trả lời của tôi là nó không quan trọng cái nào nhanh hơn vì bạn không nên tìm kiếm cùng một phần tử nhiều lần :) Nó có thể không phải là câu trả lời trực tiếp cho câu hỏi nhưng hy vọng là một giải pháp tốt cho vấn đề thực tế. –

+0

+1, không thực sự là awnser tôi đã tìm kiếm nhưng bạn chỉ ra một phần quan trọng trong tối ưu hóa mã, lưu trữ trong vars là tốt hơn sau đó làm cuộc gọi bên trong vòng lặp hơn và hơn. (không phải là mới đối với tôi btw;)) – Michael

-1

Cách thứ hai sẽ nhanh hơn vì nó biết chính xác những gì cần tìm ở mỗi bước.

Trong ví dụ này:

$('table#myId > tbody > tr > td > div.someElement'); 

Nếu không có tbody, hoặc không tr, hoặc không có td (vv), nó có thể tắt ra khỏi việc tìm kiếm ngay lập tức. Ngoài ra, mọi bước tiếp theo sẽ thu hẹp tìm kiếm (ví dụ: không tìm kiếm bên trong <thead>). So sánh với ví dụ này:

$('#myId .someElement') 

này sẽ phải quét mỗi tiểu yếu tố #myId.


Sửa: Như FelixKing chỉ ra, ví dụ đầu tiên của bạn $('#myId .someElement') thực sự là nhanh. Chỉ nhẹ, nhưng vẫn còn, nhanh hơn, vì vậy tôi nghĩ tôi nên trả lời. Sử dụng bộ chọn con (>), trái ngược với bộ chọn con cháu (một dấu cách) là phương thức truyền tải nhanh nhất, vì tập hợp các phần tử có thể ít hơn nhiều. Tuy nhiên, các trình duyệt hiện đại có các phương thức dựng sẵn được tối ưu hóa cao mà jQuery đôi khi có thể sử dụng, thực sự làm giảm thời gian thực hiện. Vì vậy, như đã thấy trong trường hợp cụ thể này, 'tệ hơn' thực sự tốt hơn, vì các trình duyệt được tối ưu hóa tốt hơn để thực hiện truy vấn cụ thể đó. Tuy nhiên, nói chung, điểm ban đầu vẫn là viết tắt, đặc biệt nếu bạn đang sử dụng thứ gì đó mà không thể được tối ưu hóa bởi trình duyệt (ví dụ như bộ chọn tùy chỉnh).

+4

Bạn có bất kỳ kết quả điểm chuẩn nào cho điều đó hoặc bạn có giả định không? Bởi vì các bài kiểm tra của tôi nói điều gì đó khác biệt. –

+1

Tôi hoàn toàn đồng ý với @Felix! Tôi không nghĩ rằng thứ hai là nhanh hơn và thực sự các bài kiểm tra kết quả là nó không! ... Tôi cũng nghĩ rằng (nếu không nhầm lẫn) nó là phương pháp tương tự như lựa chọn CSS (phải sang trái)? – ifaour

+0

Khi nó đi xuống logic tôi đưa ra kết luận tương tự, mặc dù kết quả thử nghiệm của @ ifaour chỉ ra một số khác nhau – Michael

0
'#myid .myclass' 

1) tìm thấy tất cả các yếu tố có lớp myclass
2) cho mỗi phần tử như vậy, hãy đi lên chuỗi tổ tiên của nó và dừng lại nếu bạn truy cập tổ tiên #myid. Nếu không có tổ tiên như vậy, loại bỏ các yếu tố.

Bây giờ, nó rất tốt có thể là trình duyệt tối ưu hóa quá trình này, ví dụ:

1) tìm ra #myid yếu tố
2) tìm thấy tất cả các yếu tố có lớp myclass và đó là hậu duệ của các yếu tố #myid


table#myid > tbody > tr > td > div.mylcass 

Lưu ý rằng tiền tố bộ chọn ID với một loại selector không có tác dụng, vì ID là duy nhất trong tài liệu.

#myid > tbody > tr > td > div.mylcass 

Tiền tố bộ chọn lớp có trình chọn loại tốt hơn. Vì vậy, nếu bạn biết loại phần tử, bạn được khuyến khích thiết lập nó.

Tôi không chắc về những bộ chọn con đó. Tôi đoán nó sẽ nhanh hơn nếu bạn sử dụng chúng. Nhưng nhanh hơn bao nhiêu? Có thể bỏ qua? Ngoài ra, nó trông xấu xí.

Hãy xem xét điều này:

#myid td > div.myclass 

Nếu #myid là một yếu tố bảng, và bạn không có bảng lồng nhau, sau đó chọn này nên càng nhanh càng chọn thứ hai của bạn. Tôi sẽ dùng cái này

+0

Lựa chọn CSS hoạt động theo cách này (phải sang trái), nhưng tôi không nghĩ jQuery làm. – nickf

+0

@nickf Nhưng jQuery sử dụng 'querySelectorAll()', phải không? –

+0

@ Šime - yeah * đôi khi *. Không phải nếu truy vấn là một cái gì đó querySelectorAll không thể xử lý, và không nếu trình duyệt không có chức năng đó. Trong trường hợp này, có, nhưng nói chung, không. – nickf