[英]Javascript Try-Catch Performance Vs. Error Checking Code
將代碼放入try-catch塊而不是執行各種錯誤檢查會更快嗎?
例如..
function getProjectTask(projectTaskId) {
if (YAHOO.lang.isUndefined(projectTaskId) || YAHOO.lang.isNull(projectTaskId) && !YAHOO.lang.isNumber(projectTaskId)) {
return null;
}
var projectPhaseId, projectPhaseIndex, projectTaskIndex, projectPhases, projectPhase, projectTask;
if (!YAHOO.lang.hasOwnProperty(projectTaskPhaseMap, projectTaskId)) {
return null;
}
projectPhaseId = projectTaskPhaseMap[projectTaskId];
if (YAHOO.lang.isUndefined(projectPhaseId) || YAHOO.lang.isNull(projectPhaseId) || !YAHOO.lang.hasOwnProperty(scheduleData.ProjectPhasesMap, projectPhaseId)) {
return null;
}
projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId];
if (YAHOO.lang.isUndefined(projectPhaseIndex) || YAHOO.lang.isNull(projectPhaseIndex) || !YAHOO.lang.hasOwnProperty(scheduleData.ProjectPhases[projectPhaseIndex])) {
return null;
}
projectPhase = scheduleData.ProjectPhases[projectPhaseIndex];
if (!YAHOO.lang.hasOwnProperty(projectPhase.ProjectTasksMap, projectTaskId)) {
return null;
}
projectTaskIndex = projectPhase.ProjectTasksMap[projectTaskId];
if (YAHOO.lang.isUndefined(projectTaskIndex) || YAHOO.lang.isNull(projectTaskIndex)) {
return null;
}
projectTask = scheduleData.ProjectTasks[projectTaskIndex];
}
VS
function getProjectTask(projectTaskId) {
try {
projectPhaseId = projectTaskPhaseMap[projectTaskId];
projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId];
projectPhase = scheduleData.ProjectPhases[projectPhaseIndex];
projectTaskIndex = projectPhase.ProjectTasksMap[projectTaskId];
projectTask = scheduleData.ProjectTasks[projectTaskIndex];
}
catch (e) {
return null;
}
}
我希望我的問題有道理。 我很樂意澄清。 謝謝!
“必須編寫程序供人們閱讀,並且只有偶然的機器才能執行。”
Abiz&Sussman,SICP,第一版序言
始終以可讀代碼為目標。 要記住的關鍵是:
避免在性能關鍵函數和循環中使用try-catch
在其他任何地方他們都不會造成太大傷害 明智地使用它們,謹慎使用它們。 作為旁注,如果你想支持舊瀏覽器,他們可能沒有try-catch。
但正如我看到你明顯濫用一些函數進行錯誤檢查。 您可以在使用對象之前測試所需的對象和屬性,而不是復雜的檢查。 和:
if (YAHOO.lang.isUndefined(projectPhaseId) || YAHOO.lang.isNull(projectPhaseId))
可寫成
if (projectPhaseId != null)
例如......所以上面的例子即使沒有嘗試捕獲也可以相當可讀。 你似乎有點誤用了 YUI。
我敢打賭這可以按預期工作:
function getProjectTask(projectTaskId) {
var projectPhaseId = projectTaskPhaseMap[projectTaskId],
projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId],
projectPhase = scheduleData.ProjectPhases[projectPhaseIndex];
if (projectPhase == null) return null; // projectPhase would break the chain
var projectTaskIndex = projectPhase.ProjectTasksMap[projectTaskId],
projectTask = scheduleData.ProjectTasks[projectTaskIndex];
return projectTask || null; // end of the dependency chain
}
這有多酷 ? :)
為什么沒有這個論點的事實依據? 以下代碼演示了性能影響:
var Speedy = function() {
this.init();
};
Speedy.prototype = {
init: function() {
var i, t1;
this.sumWith = 0;
this.sumWithout = 0;
this.countWith = 0;
this.countWithout = 0;
for (i = 0; i < 5; i++) {
t1 = this.getTime();
console.log("Using Try/Catch, Trial #" + (i + 1) );
console.log("started " + t1 );
this.goTry(t1);
this.countWith++;
}
for (i = 0; i < 5; i++) {
t1 = this.getTime();
console.log("W/out Try/Catch, Trial #" + (i + 1) );
console.log("started :" + t1 );
this.goAlone(t1);
this.countWithout++;
}
for (i = 5; i < 10; i++) {
t1 = this.getTime();
console.log("Using Try/Catch, Trial #" + (i + 1) );
console.log("started :" + t1);
this.goTry(t1);
this.countWith++;
}
for (i = 5; i < 10; i++) {
t1 = this.getTime();
console.log("W/out Try/Catch, Trial #" + (i + 1) );
console.log("started :" + t1);
this.goAlone(t1);
this.countWithout++;
}
console.log("---------------------------------------");
console.log("Average time (ms) USING Try/Catch: " + this.sumWith / this.countWith + " ms");
console.log("Average time (ms) W/OUT Try/Catch: " + this.sumWithout / this.countWithout + " ms");
console.log("---------------------------------------");
},
getTime: function() {
return new Date();
},
done: function(t1, wasTry) {
var t2 = this.getTime();
var td = t2 - t1;
console.log("ended.....: " + t2);
console.log("diff......: " + td);
if (wasTry) {
this.sumWith += td;
}
else {
this.sumWithout += td;
}
},
goTry: function(t1) {
try {
var counter = 0;
for (var i = 0; i < 999999; i++) {
counter++;
}
this.done(t1, true);
}
catch (err) {
console.error(err);
}
},
goAlone: function(t1) {
var counter = 0;
for (var i = 0; i < 999999; i++) {
counter++;
}
this.done(t1, false);
}
};
var s = new Speedy();
這個JSFiddle將在firebug lite的控制台中顯示輸出: http : //jsfiddle.net/Mct5N/
把教條放在一邊,暫時不滿意這里的答案......
如果您的代碼很少拋出異常,那么在犯罪者周圍放置一個try-catch表現很好,因為在捕獲異常或阻止異常時沒有額外的開銷。
如果代碼通常根據不可預測的數據或類似的情況拋出異常,那么放置一個保護方法可以大大提高性能,如果經常發生異常,則最多可以提高20倍。
如果我建議一種方法,如果沒有深度嵌套,盡可能使用簡單的防護操作員。 在更深的嵌套情況下,使用可以根據需要遍歷的保護方法。
以下是我自己的一些測試。
http://jsfiddle.net/92cp97pc/6/
場景比較以下但循環:
var a;
// scenario 1 (always throws/catches)
try { a.b.c.d; }
catch(ex) { }
// scenario 2 (about 20 times faster than scenario 1)
guard(a, 'b', 'c', 'd');
// now no exceptions will occur
a = { b: { c: { d: true } } };
// scenario 3 (too fast to measure)
try { a.b.c.d; }
catch(ex) { }
// scenario 4 (.04 times slower than scenario 3)
guard(a, 'b', 'c', 'd');
當然,它可以實現更緊湊的代碼,但它會降低您的調試能力,並使添加優雅的錯誤恢復或有用的錯誤消息變得更加困難。
取決於情況。 由於galambalazs提到可讀性很重要。 考慮:
function getCustomer (id) {
if (typeof data!='undefined' && data.stores && data.stores.customers
&& typeof data.stores.customers.getById=='function') {
return data.stores.customers.getById(id);
} else {
return null;
}
}
相比:
function getCustomer (id) {
try {return data.stores.customers.getById(id);} catch (e) { return null; }
}
我會說第二個更具可讀性。 你傾向於從google的apis或twitter的feed中獲取這樣的數據(通常不會使用深層嵌套的方法,這只是為了演示)。
當然,性能也很重要,但是現在javascript引擎足夠快,沒有人注意到差異,除非你打算每隔十毫秒調用一次getCustomer。
請記住,這也取決於瀏覽器,但總體而言,我還沒有讀到任何有關使用try / catch塊的重大性能損失的信息。 但是,使用它們並不是一個好習慣,因為你無法說明問題失敗的原因。
這是一個有趣的幻燈片放映的一些JavaScript性能考慮因素。 在幻燈片76上,它們覆蓋了try / catch塊和性能影響。 http://www.slideshare.net/madrobby/extreme-javascript-performance
性能明智的try-catch比檢查時慢20-50%( https://jsperf.com/throw-catch-vs-if-check/1 )。
因此,對於罕見的使用,沒有太大的區別。 對於大量使用,它可能會有所不同。
但是,我覺得使用try-catch是不好的做法,如果可以通過if檢查來完成,除非它大大降低了可讀性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.