2009-03-24 21 views
27

Tôi đang cố gắng tìm ra cách hiệu quả nhất để nhân bản sâu cây DOM trong trình duyệt.Nhân bản sâu so với cài đặt của innerHTML: nhanh hơn là gì?

Nếu tôi bắt đầu với

var div = document.getElementById("source"); 
var markup = div.innerHTML; 

gì sẽ nhanh hơn,

var target = div.cloneNode(true); 

hoặc

var target = document.cloneNode(false); 
target.innerHTML = markup; 

Tôi hiểu nền tảng trình duyệt có thể tạo sự khác biệt lớn ở đây, vì vậy bất kỳ thông tin về cách so sánh này trong thế giới thực sẽ được đánh giá cao.

+0

Tôi không nhận được những gì bạn đang tìm kiếm. Bạn muốn sao chép một phần tử? 'var target = div.cloneNode (true);' đã làm điều đó. Nhân bản phải làm gì với 'innerHTML'? –

+0

Các kết quả cụ thể sẽ phụ thuộc vào trình duyệt của bạn, nhưng tôi đã tìm thấy hai bài kiểm tra có liên quan tại jsPerf [ở đây] (http://jsperf.com/clonenode-vs-createelement-performance/39) và [tại đây] (http: // jsperf .com/innerclone/13). – Blazemonger

+0

[innerHTML hủy người nghe sự kiện] (http://stackoverflow.com/q/595808/1048572), không sử dụng nó. – Bergi

Trả lời

48

Hãy kiểm tra!

tôi đã thêm đoạn mã sau vào một bản sao của trang Câu hỏi StackOverflow của (loại bỏ các kịch bản hiện đầu tiên, và chạy từ đầu với một trong những timeit() s không chú thích mỗi lần xung quanh, ba chạy 100 ops:

function timeit(f) { 
    var start= new Date(); 
    for (var i=100; i-->0;) { 
     f(); 
    } 
    return new Date()-start; 
} 

var c= document.getElementById('content'); 
var clones= []; 

//alert('cloneNode: '+timeit(function() { 
// clones.push(c.cloneNode(true)); 
//})) 

//alert('innerHTML: '+timeit(function() { 
// var d= document.createElement('div'); 
// d.innerHTML= c.innerHTML; 
// clones.push(d); 
//})) 

đây là kết quả chạy trên một VirtualBox trên Core 2 Q9300:

IE7 
cloneNode: 3238, 3235, 3187 
innerHTML: 8442, 8468, 8552 

Firefox3 
cloneNode: 1294, 1315, 1289 
innerHTML: 3593, 3636, 3580 

Safari3 
cloneNode: 207, 273, 237 
innerHTML: 805, 818, 786 

Chrome1 
cloneNode: 329, 377, 426 
innerHTML: 2327, 2536, 2865 

Opera10 
cloneNode: 801, 791, 771 
innerHTML: 1852, 1732, 1672 

vì vậy cloneNode (true) được nhanh hơn nhiều so với sao chép innerHTML Tất nhiên nó đã luôn luôn có được; serialising một DOM để văn bản và. sau đó phân tích cú pháp lại từ HTML là công việc khó khăn. trên các hoạt động con DOM thường chậm là bạn đang chèn/di chuyển chúng từng người một; các hoạt động DOM tất cả cùng một lúc như cloneNode không phải làm điều đó.

Safari quản lý để thực hiện thao tác bên trong một cách nhanh chóng, nhưng vẫn không gần như nhanh như cloneNode. IE là, như mong đợi, một con chó.

Vì vậy, tự động -1 cho tất cả những người nói innerHTML rõ ràng sẽ nhanh hơn mà không xem xét câu hỏi thực sự đang làm.

Và có, jQuery sử dụng innerHTML để sao chép. Không phải vì nó là nhanh hơn mặc dù - đọc các nguồn:

// IE copies events bound via attachEvent when 
// using cloneNode. Calling detachEvent on the 
// clone will also remove the events from the orignal 
// In order to get around this, we use innerHTML. 

jQuery sử dụng Element.attachEvent() để thực hiện hệ thống sự kiện riêng của mình, vì vậy tự nhiên nó cần phải tránh lỗi đó. Nếu bạn không cần, bạn có thể tránh được phí.

[Off-chủ đề sang một bên: Sau đó, một lần nữa, tôi nghĩ rằng giữ jQuery lên là đỉnh cao của thực hành tốt nhất có thể là một chút nhầm lẫn, đặc biệt là cho các dòng tiếp theo:

html.replace(/ jQuery\d+="(?:\d+|null)"/g, "") 

Đúng vậy - jQuery thêm riêng của mình thuộc tính tùy ý cho các phần tử HTML, và sau đó cần loại bỏ chúng khi nó nhân bản chúng (hoặc cho phép truy cập vào đánh dấu của chúng, chẳng hạn như thông qua phương thức $(). html()). Điều này là đủ xấu, nhưng sau đó nó nghĩ cách tốt nhất để làm điều đó là xử lý HTML bằng cách sử dụng cụm từ thông dụng, đó là loại sai lầm cơ bản mà bạn mong đợi nhiều hơn từ những câu hỏi SO danh tiếng 1 ngây thơ hơn tác giả của Second Coming Best JS Khung Evar.

Hy vọng bạn không có chuỗi "jQuery1 =" 2 "" ở bất cứ nơi nào trong nội dung văn bản của bạn, 'cos nếu như vậy bạn chỉ mất nó một cách bí ẩn. Cảm ơn jQuery! Vì vậy, kết thúc chủ đề ngoài chủ đề.]

+0

analisys tuyệt vời. Nit nhỏ duy nhất là tôi đang tìm kiếm trước tuần tự hóa nguồn bên trongHTML một lần, không phải mọi lần trong vòng lặp. Nhưng nó vẫn còn chậm hơn. Cảm ơn. – levik

+0

Câu trả lời tuyệt vời Bobince. Chỉ cần tự hỏi, những gì * sẽ * là cách tốt nhất để thả ra các thuộc tính phụ? Chỉ tìm kiếm trong các dấu ngoặc nhọn từ danh sách trắng của các phần tử HTML hoặc tạo thành phần tử DOM và sau đó sử dụng 'removeAttr()' của jQuery trên đó? Có lẽ đó là một sự cân bằng, nó có thể nhanh hơn nhiều so với chi phí của việc mang theo bất cứ ai sử dụng chuỗi đó. Mặc dù rất hiếm, cần có một số cảnh báo trong tài liệu jQuery (tôi chưa tìm thấy nó nếu có) – alex

+0

Điều tôi muốn làm là đặt thuộc tính JS cho ID thay vì thuộc tính HTML. IE có một lỗi mà các thuộc tính được tuần tự hóa như thể chúng là các thuộc tính, nhưng nó chỉ khởi động ở nơi mà giá trị thuộc tính là một kiểu dữ liệu nguyên thủy. Thuộc tính kiểu đối tượng không được bao gồm trong 'innerHTML'. Vì vậy, thiết lập 'elementnode.jQueryId45438 = [1]' (một đối tượng mảng) sẽ cho phép jQuery đặt ID duy nhất của nó trên phần tử mà không làm rối loạn việc serialization và yêu cầu bất kỳ bản sửa lỗi post-'HTMLHTML' nào. – bobince

1

Hmmm ... thật thú vị, tôi vừa làm một thử nghiệm trong Firefox 3, và một bản sao sâu dường như nhanh gấp 3 lần so với tuyến đường innerHTML.

Tôi chắc chắn innerHTML vẫn nhanh hơn các hoạt động DOM riêng lẻ, nhưng ít nhất là để nhân bản sâu, cloneNode (true) có vẻ được tối ưu hóa tốt hơn.

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