Tôi đã nghiên cứu hiệu suất JavaScript. Tôi đã học được rằng khi truy cập nhiều hơn một lần, tốt nhất là sao chép các biến đóng và các thành viên lớp vào phạm vi cục bộ để tăng tốc mọi thứ. Ví dụ:Khi hiệu suất tinh chỉnh, cách tốt nhất để gọi các phương thức JavaScript nhiều lần là gì?
var i = 100;
var doSomething = function() {
var localI = i;
// do something with localI a bunch of times
var obj = {
a: 100
};
var objA = obj.a;
// do something with objA a bunch of times
};
Tôi hiểu điều này; nó thêm một phím tắt cho trình thông dịch tìm kiếm giá trị theo tên. Khái niệm này trở nên rất không rõ ràng khi giao dịch với các phương thức. Lúc đầu, tôi nghĩ rằng nó sẽ làm việc theo cùng một cách. Ví dụ:
var obj = {
fn: function() {
// Do something
return this.value;
},
value: 100
};
var objFn = obj.fn
objFn();
// call objFn a bunch of times
Vì vậy, điều này sẽ không hoạt động chút nào. Việc truy cập phương thức như thế này sẽ loại bỏ nó khỏi phạm vi của nó. Khi nó đạt đến dòng this.value, điều này đề cập đến đối tượng cửa sổ và this.value có thể sẽ không được xác định. Thay vì trực tiếp gọi objFn và mất phạm vi, tôi có thể vượt qua phạm vi của nó trở lại vào nó với objFn.call (obj) nhưng điều này thực hiện bất kỳ tốt hơn hoặc tồi tệ hơn sau đó obj.fn gốc()?
Tôi quyết định viết một kịch bản để kiểm tra điều này và tôi nhận được kết quả rất khó hiểu. Kịch bản lệnh này làm cho các lần lặp qua một số phép thử lặp lại thông qua hàm trên gọi nhiều lần. Thời gian trung bình cho mỗi bài kiểm tra là đầu ra cho cơ thể.
Một đối tượng được tạo bằng nhiều phương pháp đơn giản trên đó. Các phương pháp bổ sung có để xác định xem thông dịch viên có làm việc chăm chỉ hơn để định vị một phương pháp cụ thể hay không.
Kiểm tra 1 chỉ cần gọi this.a();
Kiểm tra 2 tạo biến cục bộ a = this.a rồi gọi a.call (this);
Kiểm tra 3 tạo biến cục bộ sử dụng chức năng liên kết của YUI để bảo toàn phạm vi. Tôi đã nhận xét điều này. Các cuộc gọi chức năng bổ sung được tạo bởi YUI làm theo cách này chậm hơn.
Các thử nghiệm 4, 5 và 6 là các bản sao 1, 2, 3 ngoại trừ việc sử dụng z thay vì a.
Chức năng sau của YUI được sử dụng để ngăn chặn các lỗi tập lệnh chạy trốn. Thời gian được thực hiện trong các phương pháp thử nghiệm thực tế để setTimeouts không ảnh hưởng đến kết quả. Mỗi hàm được gọi là tổng số 10000000 lần. (Dễ dàng cấu hình nếu bạn muốn chạy thử nghiệm.)
Đây là toàn bộ tài liệu XHTML tôi đã sử dụng để kiểm tra.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xml:lang="en" dir="ltr">
<head>
<script type="text/javascript" src="http://yui.yahooapis.com/combo?3.1.2/build/yui/yui-min.js"></script>
<script>
YUI().use('node', function (Y) {
var o = {
value: '',
a: function() {
this.value += 'a';
},
b: function() {
this.value += 'b';
},
c: function() {
this.value += 'c';
},
d: function() {
this.value += 'd';
},
e: function() {
this.value += 'e';
},
f: function() {
this.value += 'f';
},
g: function() {
this.value += 'g';
},
h: function() {
this.value += 'h';
},
i: function() {
this.value += 'i';
},
j: function() {
this.value += 'j';
},
k: function() {
this.value += 'k';
},
l: function() {
this.value += 'l';
},
m: function() {
this.value += 'm';
},
n: function() {
this.value += 'n';
},
o: function() {
this.value += 'o';
},
p: function() {
this.value += 'p';
},
q: function() {
this.value += 'q';
},
r: function() {
this.value += 'r';
},
s: function() {
this.value += 's';
},
t: function() {
this.value += 't';
},
u: function() {
this.value += 'u';
},
v: function() {
this.value += 'v';
},
w: function() {
this.value += 'w';
},
x: function() {
this.value += 'x';
},
y: function() {
this.value += 'y';
},
z: function() {
this.value += 'z';
},
reset: function() {
this.value = '';
},
test1: function (length) {
var time = new Date().getTime();
while ((length -= 1)) {
this.a();
}
return new Date().getTime() - time;
},
test2: function (length) {
var a = this.a,
time = new Date().getTime();
while ((length -= 1)) {
a.call(this);
}
return new Date().getTime() - time;
},
test3: function (length) {
var a = Y.bind(this.a, this),
time = new Date().getTime();
while ((length -= 1)) {
a();
}
return new Date().getTime() - time;
},
test4: function (length) {
var time = new Date().getTime();
while ((length -= 1)) {
this.z();
}
return new Date().getTime() - time;
},
test5: function (length) {
var z = this.z,
time = new Date().getTime();
while ((length -= 1)) {
z.call(this);
}
return new Date().getTime() - time;
},
test6: function (length) {
var z = Y.bind(this.z, this),
time = new Date().getTime();
while ((length -= 1)) {
z();
}
return new Date().getTime() - time;
}
},
iterations = 100, iteration = iterations, length = 100000,
t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, body = Y.one('body');
body.set('innerHTML', '<span>Running ' + iterations + ' Iterations…</span>');
while ((iteration -= 1)) {
Y.later(1, null, function (iteration) {
Y.later(1, null, function() {
o.reset();
t1 += o.test1(length);
});
Y.later(1, null, function() {
o.reset();
t2 += o.test2(length);
});
/*Y.later(1, null, function() {
o.reset();
t3 += o.test3(length);
});*/
Y.later(1, null, function() {
o.reset();
t4 += o.test4(length);
});
Y.later(1, null, function() {
o.reset();
t5 += o.test5(length);
});
/*Y.later(1, null, function() {
o.reset();
t6 += o.test6(length);
});*/
if (iteration === 1) {
Y.later(10, null, function() {
t1 /= iterations;
t2 /= iterations;
//t3 /= iterations;
t4 /= iterations;
t5 /= iterations;
//t6 /= iterations;
//body.set('innerHTML', '<dl><dt>Test 1: this.a();</dt><dd>' + t1 + '</dd><dt>Test 2: a.call(this);</dt><dd>' + t2 + '</dd><dt>Test 3: a();</dt><dd>' + t3 + '</dd><dt>Test 4: this.z();</dt><dd>' + t4 + '</dd><dt>Test 5: z.call(this);</dt><dd>' + t5 + '</dd><dt>Test 6: z();</dt><dd>' + t6 + '</dd></dl>');
body.set('innerHTML', '<dl><dt>Test 1: this.a();</dt><dd>' + t1 + '</dd><dt>Test 2: a.call(this);</dt><dd>' + t2 + '</dd><dt>Test 4: this.z();</dt><dd>' + t4 + '</dd><dt>Test 5: z.call(this);</dt><dd>' + t5 + '</dd></dl>');
});
}
}, iteration);
}
});
</script>
</head>
<body>
</body>
</html>
Tôi đã chạy tính năng này bằng Windows 7 trong ba trình duyệt khác nhau. Các kết quả này tính bằng mili giây.
Firefox 3.6.8
Test 1: this.a();
9.23
Test 2: a.call(this);
9.67
Test 4: this.z();
9.2
Test 5: z.call(this);
9.61
Chrome 7.0.503.0
Test 1: this.a();
5.25
Test 2: a.call(this);
4.66
Test 4: this.z();
3.71
Test 5: z.call(this);
4.15
Internet Explorer 8
Test 1: this.a();
168.2
Test 2: a.call(this);
197.94
Test 4: this.z();
169.6
Test 5: z.call(this);
199.02
Firefox và Internet Explorer được sản xuất kết quả về cách tôi mong đợi. Kiểm tra 1 và Test 4 tương đối gần, Test 2 và Test 5 tương đối gần, và Test 2 và Test 5 mất nhiều thời gian hơn Test 1 và Test 4 vì có thêm một cuộc gọi hàm để xử lý.
Chrome Tôi không hiểu chút nào, nhưng nó nhanh hơn rất nhiều, có lẽ việc tinh chỉnh hiệu suất phụ phần nghìn giây là không cần thiết.
Có ai có giải thích tốt về kết quả không? Cách tốt nhất để gọi các phương thức JavaScript nhiều lần là gì?
bạn có thể thêm liên kết này trong câu hỏi của bạn, vì vậy những người dùng khác có thể chạy các bài kiểm tra bản thân? - http://jsfiddle.net/Lbbx5/ – Anurag
Đọc liên quan: [JavaScript Widget Không có "này"] (http://michaux.ca/articles/javascript-widgets-without-this) –
FYI, sử dụng Chromium (Linux) trên hệ thống của tôi (tương đối chậm), sau một vài thử nghiệm có vẻ như kết quả giống như trong Firefox (chỉ nhanh hơn): kết hợp 1/4 và 2/5 gần bằng hoặc ít hơn và 2 và 5 chậm hơn 1 và 4. –