2013-05-24 68 views
6

Bất cứ khi nào có lỗi xuất hiện bên trong trình xử lý sự kiện, nó dừng hoàn toàn việc thực thi mã để gọi lại sự kiện thứ hai không được gọi.Lỗi Javascript dừng thực thi mã

Ví dụ:

$(function() { 
    window.thisDoesntExist(); 
} 
$(function() { 
    //Do something unharmful and unrelated to the first event 
} 

Bạn có thể dễ dàng giải quyết vấn đề trong việc này (giản thể) ví dụ bằng cách thêm try/catch trong cả hai chức năng ẩn danh, nhưng trong thực tế các chức năng này thường thêm một số xử lý sự kiện khác mà lần lượt sẽ yêu cầu try/catch. Tôi kết thúc với mã rất lặp đi lặp lại nhồi với khối try/catch.

Dự án của tôi có thiết kế kiểu mô-đun trong đó mỗi đối tượng địa lý nằm trong một JS khác (và được ghép nối trong quá trình xây dựng). Tôi đang tìm một cách chung chung hơn để xử lý các lỗi bên trong mỗi tính năng để các lỗi không ngừng thực thi mã của các tính năng khác.

Tôi đã cố gắng giải pháp sau: - window.onerror (ngay cả khi bạn trở thành sự thật trong hàm này, mã thực thi được dừng) - $ (window) .error() => bị phản đối và thực thi mã dừng

+0

Bạn đã đọc câu hỏi của tôi chưa? Bạn có thể dễ dàng giải quyết vấn đề trong ví dụ này (đơn giản) bằng cách thêm try/catch vào cả hai hàm ẩn danh, nhưng trong thực tế, các hàm này thường thêm một số trình xử lý sự kiện khác, do đó sẽ yêu cầu try/catch. Tôi kết thúc với mã rất lặp đi lặp lại nhồi với khối try/catch. – Webberig

+0

Có lẽ đó là sự thỏa hiệp mà bạn phải thực hiện nếu bạn muốn mã của mình mạnh mẽ nhất có thể. – CBroe

+0

@Webberig, tôi chắc chắn. Yêu cầu cơ bản bạn cần là tiếp tục chạy mã trên (bất kỳ) lỗi nào. Cách duy nhất là sử dụng try catch. Đây là bước đầu tiên. Sau đó, bạn có thể sử dụng một cuộc gọi lại lỗi hoặc phát ra một sự kiện lỗi hoặc bất cứ điều gì để làm cho lỗi của bạn xử lý vững chắc và linh hoạt. Bạn có thể tham khảo mã nguồn của Requirejs, nó cũng sử dụng try catch. https://github.com/jrburke/requirejs/blob/master/require.js –

Trả lời

-2

Tôi đã tìm được giải pháp. Khi sử dụng setTimeout, mã được thực hiện trong một chuỗi riêng biệt, nó sẽ không phá vỡ bất kỳ phần nào khác của trang web.

$(function() { 
    setTimeout(function() { 
    window.thisDoesntExist(); 
    }, 0); 
}); 
$(function() { 
    setTimeout(function() { 
     //Do something unharmful and unrelated to the first event 
     alert("This passes") 
    }, 0); 
}); 

Trong ví dụ này, chức năng thứ hai được chạy, ngay cả khi chức năng thứ nhất phát sinh lỗi. Dưới đây là một ví dụ làm việc: http://jsfiddle.net/mathieumaes/uaEsy/

+1

+1 vì tôi đã học được điều gì đó -1 vì đây là một hack siêu tổng – mpd

+2

Hàm tham chiếu của setTimout không hoạt động trong một chuỗi riêng biệt. Chồng thực thi của một thời gian chạy JavaScript là đơn luồng. Những gì thực sự xảy ra là khi lỗi của bạn được xử lý bởi callback onerror của bạn, stack thực hiện đang được xóa (đó là lý do tại sao không có mã bổ sung được chạy sau khi lỗi của bạn).setTimeout làm cho hàm tham chiếu được đặt trong hàng đợi sự kiện và các sự kiện trong hàng đợi đó chạy khi ngăn xếp thực hiện rõ ràng. Nó hoạt động, nhưng không phải vì đa luồng. – user1739635

+0

Ngoài ra, thứ tự không được đảm bảo khi chạy không đồng bộ, phụ thuộc vào việc triển khai thực hiện, nếu các tác vụ đó cần phải xảy ra theo thứ tự, bạn sẽ tạo điều kiện cho cuộc đua. Tôi giả định từ ngữ cảnh rằng trật tự không quan trọng ở đây nhưng là một giải pháp chung, điều này là có vấn đề. – guioconnor

5

Bạn có thể tạo một hàm trợ giúp để ngăn trùng lặp của cùng một mã bản mẫu.

function tryFunction(f, onerror) { 
    try { 
     if (typeof f == 'function') { 
      return f(); 
     } 
    } catch (e) { 
     return onerror(e); 
    } 
} 

$(function() { 
    var result = tryFunction(window.thisDoesNotExist, function (error) { 
     alert('Whoops: ' + error); 
    }); 
}); 

I created a little demonstration. Đó là hơi khác nhau nhưng cùng một ý tưởng.

0

Bạn chỉ có thể gọi if (typeof myFunction == 'function') trước khi gọi myFunction()

Và tùy chọn bọc nó trong một chức năng chung chung như đã nói bởi Bart để có sự lựa chọn để đăng nhập một lỗi trong giao diện điều khiển nếu chức năng của bạn không tồn tại.

Nếu webapp của bạn là rất lớn với nhiều tương tác và JS, quá nhiều try catch có thể thay đổi hiệu suất toàn cầu của ứng dụng của bạn.

0

tôi sẽ cố gắng một cái gì đó như thế này với một wrapper mà sẽ xử lý catch cho bạn (xem dưới đây, hoặc jsfiddle này: http://jsfiddle.net/TVfCj/2/)

Từ cách tôi (không, và không thực sự) xử lý này và các đối số, tôi đoán rõ ràng là tôi bắt đầu bằng js. Nhưng tôi hy vọng bạn có được ý tưởng, và nó là chính xác/hữu ích.

var wrapper = { 
     wrap: function wrap(f) { 
      return function (args) { 
       try { 
        f.apply(null, args); 
       } catch (ex){ 
        console.log(f.name+" crashed with args "+args); 
       }; 
      }; 
     } 
    }; 

    var f1 = function f1Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 
    var f2 = function f2Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 

    var f3 = function f3MustNotCrash(arg) { 
     wrapper.wrap(f1)(arg); 
     wrapper.wrap(f2)(arg); 
    } 

    f3('myarg'); 
0

Các try - mẫu catch bạn đề cập đến nỗ lực trong câu hỏi của bạn là cách chính xác - bạn muốntry-catch khối, không một cách để âm thầm xe tải qua lỗi mô-đun (nói chung luôn luôn xử lý các trường hợp ngoại lệ cực kỳ cẩn thận trên toàn cầu và tiếp tục, theo cách đó, các lỗi tham nhũng dữ liệu bạn chỉ tìm thấy sau 6 tháng).

vấn đề thực sự của bạn là thế này:

... trong thực tế các chức năng này thường thêm một số xử lý sự kiện khác mà đến lượt nó sẽ đòi hỏi try/catch. Tôi kết thúc với mã rất lặp đi lặp lại nhồi với khối try/catch.

Sửa chữa cho điều đó là Promise. Đây là một cấu trúc mới, có nguồn gốc ở hầu hết các trình duyệt nhưng dễ dàng bị mờ trong các trình duyệt chậm (ahem, IE), cung cấp cho bạn một cách tiêu chuẩn để quản lý cả sự kiện gọi lại ngoại lệ từ sự kiện.

Với mã số Promise, hãy hứa sẽ luôn làm điều gì đó: giải quyết/thành công hoặc từ chối/thất bại.

function moduleA() { 
    return new Promise(function (resolve, reject) 
    { 
     try{ 
      var result = window.thisDoesntExist(); 
      resolve(resolve); // Success! 
     } 
     catch(err){ 
      reject(err); // Fail! 
     } 
    }); 
} 

Đây là tốt hơn bởi vì thay vì tổ try-catch khối trong từng gọi lại bạn có thể thay vì chuỗi những lời hứa:

moduleA(). 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from A, B, or C 

Bạn cũng có thể xử lý một lỗi và tiếp tục:

moduleA(). 
    catch(continuableErrorHandler). // Catch any error from A 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from B or C 

Bạn vẫn sẽ cần nhiều khối try - catch trong các cuộc gọi lại, nhưng mọi thứ đã được gói trong một Promise có thể được xử lý theo cùng một cách mô-đun.

Tiếp theo trong JS là asyncawait, nhưng bạn có thể sử dụng chúng ngay bây giờ bằng trình chuyển đổi. Những lời hứa này sử dụng để làm cho mã dễ đọc hơn nhiều, và quan trọng nhất (đối với bạn) có một đơn try - catch ở trên cùng thu thập ngoại lệ từ toàn bộ chuỗi Promise.

Câu trả lời này đã quá dài, nhưng tôi đã blogged about that in more detail.

TL; DR: Nếu vấn đề của bạn là "rất lặp đi lặp lại [sự kiện callback] đang nhồi với các khối try/catch" hãy thử sử dụng Promise để thay thế.

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