2009-12-04 41 views
6

Ai đó có thể chứng minh cho tôi rằng lời khuyên được đưa ra here (sao chép bên dưới) về việc loại bỏ các phần tử dom trước khi thay đổi chúng và sau đó chèn lại chúng nhanh hơn bao giờ hết.Hiệu suất Javascript - Dom Reflow - Điều Google

Bằng chứng, tôi muốn xem một số số liệu. Điều tuyệt vời của họ là họ nghiên cứu điều này nhưng tôi nghĩ bài viết rất yếu mà không bao gồm chi tiết cụ thể về vấn đề 'thực sự' là gì và cách sửa lỗi giải pháp là tốc độ (như tiêu đề bài viết Tăng tốc JavaScript)

Điều ....

Out-of-the-dòng chảy DOM Manipulation

mô hình này cho phép chúng tôi tạo ra nhiều yếu tố và chèn chúng vào DOM kích hoạt một reflow duy nhất. Nó sử dụng một cái gì đó gọi là DocumentFragment. Chúng tôi tạo ra một DocumentFragment bên ngoài DOM (vì vậy nó là out-of-the-flow). Sau đó chúng tôi tạo và thêm nhiều yếu tố vào điều này. Cuối cùng, chúng ta di chuyển tất cả các phần tử trong DocumentFragment sang DOM nhưng kích hoạt một reflow đơn. Sự cố

Hãy tạo một hàm thay đổi thuộc tính className cho tất cả các neo trong phần tử. Chúng ta có thể làm điều này bằng cách đơn giản lặp qua từng anchor và cập nhật các thuộc tính href của chúng. Vấn đề là, điều này có thể gây ra một reflow cho mỗi neo.

function updateAllAnchors(element, anchorClass) { 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
} 

Giải pháp

Để giải quyết vấn đề này, chúng ta có thể loại bỏ yếu tố từ DOM, cập nhật tất cả neo, và sau đó chèn phần tử trở lại nơi nó được. Để giúp đạt được điều này, chúng ta có thể viết một hàm có thể tái sử dụng không chỉ loại bỏ một phần tử từ DOM, mà còn trả về một hàm sẽ chèn phần tử trở lại vị trí ban đầu của nó.

/** 
* Remove an element and provide a function that inserts it into its original position 
* @param element {Element} The element to be temporarily removed 
* @return {Function} A function that inserts the element into its original position 
**/ 
function removeToInsertLater(element) { 
    var parentNode = element.parentNode; 
    var nextSibling = element.nextSibling; 
    parentNode.removeChild(element); 
    return function() { 
    if (nextSibling) { 
     parentNode.insertBefore(element, nextSibling); 
    } else { 
     parentNode.appendChild(element); 
    } 
    }; 
} 

Bây giờ chúng tôi có thể sử dụng chức năng này để cập nhật các neo trong phần tử, và chỉ kích hoạt reflow khi chúng ta loại bỏ phần tử và khi chúng ta chèn phần tử.

function updateAllAnchors(element, anchorClass) { 
    var insertFunction = removeToInsertLater(element); 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
    insertFunction(); 
} 

Trả lời

5

Bạn sẽ thấy khó để có được con số có ý nghĩa cho điều này từ javascript profiling như bạn đang thực sự tiết kiệm repaints và tái dòng mà sẽ không hiển thị trong hầu hết các công cụ profiling. Bạn có thể sử dụng Firebug paint events extension để hiển thị trực quan cho bạn số lượng bản sao bạn đang lưu.

+0

Tuy nhiên, cả hai ví dụ đều có vẻ tương tự như vậy đối với tôi. Bất kỳ cơ hội nào bạn có thể đưa ra demo tại pastebin.me :) – redsquare

+0

Tôi sẽ thừa nhận rằng tiện ích mở rộng làm chậm mọi thứ xuống rất nhiều vì vậy đôi khi khó có thể thấy sự khác biệt về các hoạt động nặng tính toán, ví dụ: Google Maps thu phóng. – Alex

1

Câu trả lời ngắn gọn là thay đổi đối với DOM của trang kích hoạt Javascript thực tế các sự kiện, đánh giá CSS, tuyên truyền về những thay đổi ảnh hưởng về việc giải thích phần còn lại của DOM xung quanh nó, vv nút ngắt kết nối thay đổi liên tục không có gì giống như kết nối với họ, và các thao tác trên chúng rẻ hơn nhiều.

Tương tự: Nếu bạn là một nhà làm phim hoạt hình trên Toy Story 4, và trong một kết quả gần bạn thấy một sự thay đổi bạn cần để thực hiện trong vật lý vải của một cảnh, bạn sẽ thực hiện thay đổi của bạn trong khi làm đầy đủ xem lại chi tiết để kiểm tra cảnh, hoặc tắt họa tiết và màu sắc và giảm độ phân giải trong khi bạn thực hiện những thay đổi đó?

+0

Tôi muốn nhân vật. Những lợi ích ở đâu. Lý thuyết là tuyệt vời. Cũng giống như Iraq có WOMD, hãy nhìn xem chuyện gì đã xảy ra. Tôi vẫn không thấy làm thế nào nó làm cho js nhanh hơn. Tôi đã lược tả nó và không thấy lợi ích gì cả. Chỉ cần tự hỏi những gì tôi đã mất tích. – redsquare

+0

@redsquare: Tiêu đề của bài viết đó là gây hiểu nhầm và theo một số cách không chính xác. Nó không nhất thiết làm cho JS nhanh hơn ... nó giúp trình duyệt hiển thị DOM nhanh hơn. Nói cách khác, JS có thể chạy nhanh (hoặc thậm chí chậm hơn), nhưng trang sẽ xuất hiện nhanh hơn, bởi vì trình duyệt phải mất ít thời gian hơn để phản xạ và sơn lại. Phản chiếu và sơn lại là cách trình duyệt hiển thị HTML và CSS. Hiệu suất JS không giống như hiệu suất hiển thị của trình duyệt. Ví dụ, các bảng tốn kém để hiển thị, ngay cả khi trang web của bạn không có JS. – Pauan

+0

@redsquare: Tôi nghĩ lý do họ gọi nó là "tăng tốc JavaScript" là bởi vì JS là * thường * điều kích hoạt sự phản xạ và sơn lại. Nói cách khác, bằng cách thay đổi mã JS của bạn, bạn có thể làm cho trang xuất hiện nhanh hơn. Nhưng nó không xuất hiện nhanh hơn vì JS nhanh hơn, nó xuất hiện nhanh hơn vì trình duyệt đang phản xạ và vẽ lại ít hơn. Ví dụ, một Java applet điều khiển DOM có thể sẽ chỉ là xấu, vì vậy nó không chính xác để gọi nó là "tốc độ JavaScript". Nó thực sự là tốc độ dựng hình. – Pauan

2

Tôi đặt một số liên kết trên một trang và thử nghiệm phương pháp trong bài viết so với cài đặt tên lớp với các yếu tố vẫn còn trong trang. Tôi đã thử điều này trong Firefox 3, IE 8 và Chrome 3.

Tôi đã tạo các lớp cho các liên kết có màu sắc khác nhau và kích thước phông chữ khác nhau.Vì văn bản liên kết có kích thước khác nhau cho các lớp khác nhau, tôi chắc chắn rằng trang thực sự phải được chỉnh lại.

Đối với bất kỳ số lượng liên kết hợp lý nào (tối đa một vài nghìn), việc xóa và thêm các phần tử hơi chậm hơn.

Đối với số lượng liên kết cực lớn (10 000), việc xóa và thêm các phần tử sẽ nhanh hơn một chút.

Tuy nhiên, sự khác biệt là khá nhỏ. Bạn phải có vài nghìn liên kết để có thể nhận thấy bất kỳ sự khác biệt nào, và ở 10 000 liên kết vẫn chỉ có một cái gì đó giống như một sự khác biệt 20%.

Vì vậy, những gì tôi đã tìm thấy là bạn không thể mong đợi bất kỳ thay đổi đáng kể nào từ phương pháp này. Nếu bạn gặp vấn đề về hiệu năng, có thể có các phương pháp khác mang lại kết quả tốt hơn nhiều. Ví dụ, tôi sẽ thử thay đổi tên lớp của phần tử cha thay vì tất cả các phần tử con và cho phép CSS thực hiện công việc. Thử nghiệm tôi đã làm trước đây cho thấy rằng điều này có thể nhanh hơn khoảng mười lần.

0

Không có cách nào đáng tin cậy để biết thời điểm chỉnh sửa đã hoàn thành, ngoại trừ việc xem trang.

Thời gian dành tính hầu như giống nhau để thêm hoặc thay đổi các thành phần cùng một lúc hoặc từng cái một. Tập lệnh không chờ trình duyệt giữa các phần tử, trình duyệt bắt kịp.

Đôi khi bạn muốn xem nội dung nào đó ngay lập tức, ngay cả khi mất nhiều thời gian hơn để hiển thị toàn bộ thời gian khác mà bạn muốn đợi lâu hơn một chút và hiển thị tất cả khi nó sẵn sàng.

Nếu bạn không thể biết điều nào tốt hơn, hãy để một nhà thiết kế xem xét từng phiên bản một và tất cả cùng một lúc - nhưng đừng hỏi hai nhà thiết kế!

2

Điều này ít nhiều giống với việc sử dụng documentFragments để khởi tạo các phần tử thay vì phần tử dom. Các mảnh tài liệu kết thúc nhanh hơn bởi vì chúng có cấu trúc ít hơn và kết xuất thực tế để lo lắng.

Dưới đây là một số ghi chú John Resig về những lợi ích hiệu suất của mảnh tài liệu (mà đang được sử dụng trong jquery hiện tại):

http://ejohn.org/blog/dom-documentfragments/

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