2011-12-22 52 views
10

Cuộn xuống cho số getById.getByClassName so với qSA so sánh!


Nếu chúng ta muốn chọn tất cả các yếu tố của lớp "bar" mà là bên trong phần tử với ID "foo", chúng ta có thể viết này:

$('#foo .bar') 

hay này:

$('.bar', '#foo') 

Có tất nhiên là các phương pháp khác để đạt được điều này, nhưng vì lợi ích của câu hỏi này, chúng ta hãy so sánh chỉ hai phương pháp này.

Vì vậy, phương pháp nào ở trên hoạt động tốt hơn? (Trong đó cần ít thời gian hơn để thực hiện?)

Tôi đã viết bài kiểm tra hiệu suất này:

(function() { 
    var i; 

    console.time('test1'); 
    for(i = 0; i < 100; i++) { 
     $('#question-mini-list .tags'); 
    } 
    console.timeEnd('test1'); 

    console.time('test2'); 
    for(i = 0; i < 100; i++) { 
     $('.tags', '#question-mini-list'); 
    } 
    console.timeEnd('test2'); 
})(); 

Bạn phải thực hiện nó từ bên trong giao diện điều khiển trên Stack Overflow bắt đầu trang. kết quả của tôi là:

Firefox:
test1: ~ 90ms
test2: ~ 18ms

Chrome:
test1: ~ 65ms
test2: ~ 30ms

Opera:
test1: ~ 50ms
test2: ~ 100ms

Vì vậy, trong Firefox và Chrome, t phương pháp thứ hai của anh ta nhanh gấp nhiều lần - đúng như tôi mong đợi. Tuy nhiên, trong Opera tình hình được đảo ngược. Tôi tự hỏi chuyện gì đang xảy ra ở đây.

Bạn có thể chạy thử nghiệm trên máy của mình và giải thích lý do Opera hoạt động khác nhau không?


Cập nhật

Tôi đã viết bài kiểm tra này, để điều tra xem liệu của Opera QSA thực sự là siêu nhanh. Khi nó quay ra, nó được.

(function() { 
    var i, limit = 5000, test1 = 'test1', test2 = 'test2'; 

    console.time(test1); 
    for(i = 0; i < limit; i += 1) { 
     document.getElementById('question-mini-list').getElementsByClassName('tags'); 
    } 
    console.timeEnd(test1); 

    console.time(test2); 
    for(i = 0; i < limit; i += 1) { 
     document.querySelectorAll('#question-mini-list .tags'); 
    } 
    console.timeEnd(test2); 
})(); 

Một lần nữa, bạn phải chạy mã này từ bên trong bảng điều khiển trên trang bắt đầu tràn ngăn xếp. Tôi đã sử dụng bookmarklet Firebug Lite cho IE9 (vì trình duyệt đó không thực hiện console.time).

Vì vậy, tôi so với phương pháp này:

document.getelementById('A').getElementsByClassName('B'); 

phương pháp này:

document.querySelectorAll('#A .B'); 

Tôi đã thực hiện kịch bản trên năm lần liên tiếp trong mỗi trình duyệt.Các phương tiện số học là:

enter image description here

(Tất cả các con số trong mili giây.)

Vì vậy, việc thực hiện các phương pháp đầu tiên là khá nhiều như nhau trong các trình duyệt thử nghiệm (16-36ms). Tuy nhiên, trong khi qSA là chậm hơn nhiều so với phương pháp đầu tiên, trong Opera nó thực sự là nhanh hơn!

Vì vậy, QSA tối ưu hóa là có thể, tôi tự hỏi những gì mà các trình duyệt khác đang chờ đợi ...

+0

'test1: 73ms',' test2: 11ms'. Opera là một trình duyệt lạ, tôi không chắc tại sao nó lại bị chậm lại. – Blender

+1

@Blender Vui lòng tăng giới hạn vòng lặp. Máy tính xách tay của tôi là rất chậm, vì vậy tôi đã đi với 100. Hãy thử 1000.(Các kết quả nhỏ hơn '4ms' không đáng tin cậy ...) –

+0

Bạn đã bao gồm cả' document.getElementById ('foo'). GetElementsByClassName ('bar') 'cho đầy đủ? – RobG

Trả lời

3

jQuery/Sizzle sẽ tránh sử dụng công cụ Sizzle dựa trên JavaScript nếu trình duyệt hỗ trợ querySelectorAll và nếu bạn chuyển bộ chọn hợp lệ (không có bộ chọn tùy chỉnh, không phải CSS).

Điều này có nghĩa là cuối cùng bạn đang so sánh việc triển khai querySelectorAll, giả sử bạn đang thử nghiệm các trình duyệt hỗ trợ nó.

Có các tối ưu hóa khác mà jQuery hoặc Sizzle sử dụng, vì vậy nó rất khó khi so sánh các loại lựa chọn DOM khác nhau trong các trình duyệt khác nhau.

Lý do kết quả hoạt động của Opera có vẻ như là chúng có hiệu suất tối ưu hóa rất cao được thực hiện querySelectorAll. qSA, là một phương pháp tương đối mới, chưa được tối ưu hóa trong một số trình duyệt so với các phương pháp cũ hơn như getElementsByTagName.

+0

Vâng, qSA không phải là mới. Đó là trong Chrome kể từ khi mãi mãi, trong Firefox kể từ 3,5, và trong IE từ 8. Các trình duyệt có rất nhiều thời gian để tối ưu hóa nó. Xấu hổ với họ (kiểm tra bài kiểm tra mới của tôi ở trên). –

+0

@ ŠimeVidas: Có, mới chỉ liên quan đến một số phương pháp khác. Nhưng bạn nói đúng. Dường như với tôi rằng họ đã có nhiều thời gian để tối ưu hóa. Tôi chắc chắn họ sẽ đi xung quanh cuối cùng. –

+0

@ ŠimeVidas: Tôi sẽ ném một khả năng khác ra khỏi đó. Vì thử nghiệm của bạn không làm bất cứ điều gì với kết quả, tôi tự hỏi nếu tối ưu hóa là không bận tâm với việc lựa chọn DOM ở tất cả. Có lẽ nó gọi phương thức, nhưng từ bỏ tìm kiếm. Điều này có thể giải thích tại sao thử nghiệm đầu tiên mất nhiều thời gian hơn (hai cuộc gọi chức năng). Đây là suy đoán thuần túy tất nhiên. –

1

Và người chiến thắng là ....

thử nghiệm 3$('#question-mini-list').find('.tags');

  • test1: 25ms
  • test2: 19ms
  • test3: 10ms

Hai phương pháp bạn đề xuất không tương đương.

kiểm tra 1: Phân tích nhanh từ phải sang trái (không yêu cầu tìm kiếm phần tử bao giờ trên trang, sau đó hạn chế ID).

kiểm tra 2: Sử dụng chuỗi như ngữ cảnh thường không được sử dụng, hãy sử dụng các phần tử làm ngữ cảnh.

kiểm tra 3: Tìm các thành phần có id nhanh chóng. Khi bạn ở đó, bạn sẽ dễ dàng tập trung vào một mục của một lớp nhất định.

+0

"* Sizzle phân tích từ phải sang trái *" - Tôi rất thích một nguồn cho điều đó. –

+1

Sizzle có tối ưu hóa rằng nếu chuỗi bắt đầu bằng bộ chọn id, [nó sử dụng đầu tiên đó] (http://stackoverflow.com/questions/7757744/will-jquery-search-for-the-id-before-filtering- other-parameters-in-the-selector/7757792 # 7757792), vì vậy chúng phải tương đương nhau. – Dennis

+0

jQuery biến '$ ('. Bar', '#foo')' thành '$ ('# foo'). Tìm ('. Bar')' nội bộ. Tôi coi chúng là tương đương. Sau này là hơi nhanh hơn tất nhiên. –

1

Để tham khảo, đây là 30x nhanh hơn:

document.getElementById("foo").getElementsByClassName("bar"); 

Xem jsPerf: http://jsperf.com/jquery-selector-variations/3. Điều này sẽ cần một shim để làm việc trong các phiên bản cũ của IE.

Trong khi jQuery cực kỳ hữu ích, nếu tốc độ tối đa, nó không phải lúc nào cũng là công cụ tốt nhất cho công việc.

+0

Thanh "Đồng bằng JS" đã hủy hoại biểu đồ ': P' –

+0

@ ŠimeVidas - Vâng, tôi cũng nhận thấy điều đó. Tôi đã không mong đợi một sự khác biệt đáng kể như vậy. Bạn có thể quay lại phiên bản trước nếu bạn muốn. Loại đi để hiển thị bao nhiêu chi phí, có thể có trong cả hai phân tích cú pháp một bộ chọn mục đích chung và trong các đối tượng jQuery nói chung. – jfriend00

Các vấn đề liên quan