Sau đây là một bản tóm tắt và tuyển chọn từ nhiều nguồn khác nhau về chủ đề này bao gồm ví dụ mã và trích dẫn từ các bài đăng trên blog được chọn. Danh sách đầy đủ các thực hành tốt nhất có thể được tìm thấy ở đây
Thực hành tốt nhất về xử lý lỗi Node.JS
Số 1: Sử dụng lời hứa để xử lý lỗi không đồng bộ
TL; DR: Xử lý các lỗi không đồng bộ theo kiểu gọi lại có lẽ là cách nhanh nhất để xuống địa ngục (còn gọi là kim tự tháp của sự diệt vong). Món quà tốt nhất bạn có thể tặng cho mã của mình là sử dụng thay vào đó là thư viện lời hứa có uy tín cung cấp cú pháp mã nhỏ gọn và quen thuộc như thử bắt
Nếu không thì:Mặt Kiểu gọi lại của Node.JS, hàm (err, hồi đáp), là một cách đầy hứa hẹn cho mã không thể bảo trì do sự pha trộn xử lý lỗi với mã thông thường, các mẫu mã lồng nhau quá mức và lúng túng
Mã ví dụ - tốt
doWork()
.then(doWork)
.then(doError)
.then(doWork)
.catch(errorHandler)
.then(verify);
mã ví dụ chống mẫu - xử lý lỗi kiểu gọi lại
getData(someParameter, function(err, result){
if(err != null)
//do something like calling the given callback function and pass the error
getMoreData(a, function(err, result){
if(err != null)
//do something like calling the given callback function and pass the error
getMoreData(b, function(c){
getMoreData(d, function(e){
...
});
});
});
});
});
Trích dẫn trên blog: "Chúng tôi gặp vấn đề với lời hứa"
(Từ blogbagdb, xếp hạng 11 cho từ khóa "Lời hứa của nút")
"Thực tế, các cuộc gọi lại làm một điều gì đó thậm chí còn độc ác hơn: chúng tước đoạt của chúng ta trong ngăn xếp, đó là điều mà chúng ta thường được cấp trong các ngôn ngữ lập trình. Viết mã mà không có ngăn xếp giống như lái xe không có bàn đạp phanh: bạn đừng nhận ra bạn cần nó tệ đến mức nào, cho đến khi bạn đạt được nó và nó không ở đó. Toàn bộ lời hứa là trả lại cho chúng tôi những nguyên tắc cơ bản về ngôn ngữ mà chúng tôi đã mất khi chúng tôi không đồng bộ: trả lại, ném và chồng. phải biết sử dụng lời hứa một cách chính xác để tận dụng lợi thế của chúng. "
Số2: Chỉ sử dụng đối tượng Lỗi tích hợp
TL; DR: Khá phổ biến khi thấy mã ném lỗi dưới dạng chuỗi hoặc dưới dạng tùy chỉnh - điều này làm phức tạp logic xử lý lỗi và khả năng tương tác giữa các mô-đun. Cho dù bạn từ chối lời hứa, ném ngoại lệ hoặc phát ra lỗi - sử dụng đối tượng Lỗi tích hợp Node.JS sẽ tăng tính đồng nhất và ngăn ngừa mất thông tin lỗi
Mặt khác: Khi thực hiện một số mô-đun, không chắc chắn loại lỗi nào sẽ quay trở lại - làm cho khó khăn hơn nhiều để lý do về ngoại lệ sắp tới và xử lý nó. Thậm chí giá trị, sử dụng các loại tùy chỉnh để mô tả lỗi có thể dẫn đến mất thông tin lỗi nghiêm trọng như theo dõi ngăn xếp!
Mã ví dụ - làm đúng
//throwing an Error from typical function, whether sync or async
if(!productToAdd)
throw new Error("How can I add new product when no value provided?");
//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
//'throwing' an Error from a Promise
return new promise(function (resolve, reject) {
DAL.getProduct(productToAdd.id).then((existingProduct) =>{
if(existingProduct != null)
return reject(new Error("Why fooling us and trying to add an existing product?"));
mã ví dụ chống mẫu
//throwing a String lacks any stack trace information and other important properties
if(!productToAdd)
throw ("How can I add new product when no value provided?");
Trích dẫn trên blog: "Chuỗi không phải là lỗi"
(Từ suy nghĩ của blog, xếp hạng 6 cho các từ khóa Từ Node.JS đối tượng lỗi đối tượng)
"Truyền qua chuỗi thay vì lỗi dẫn đến giảm khả năng tương tác giữa các mô-đun. Nó phá vỡ hợp đồng với các API có thể đang thực hiện kiểm tra lỗi, hoặc muốn biết thêm về lỗi . Các đối tượng lỗi, như chúng ta sẽ thấy, rất các thuộc tính thú vị trong các công cụ JavaScript hiện đại bên cạnh việc giữ thông điệp được chuyển đến hàm tạo .. "
Số 3: Phân biệt lỗi vận hành và lỗi lập trình viên
TL; DR: Lỗi hoạt động (ví dụ: API nhận được đầu vào không hợp lệ) đề cập đến các trường hợp đã biết trong đó tác động lỗi được hiểu đầy đủ và có thể được xử lý chu đáo. Mặt khác, lỗi lập trình viên (ví dụ: cố gắng đọc biến không xác định) đề cập đến các lỗi mã không xác định có nghĩa là khởi động lại ứng dụng một cách duyên dáng
Nếu không thì: Bạn luôn có thể khởi động lại ứng dụng khi có lỗi xuất hiện, nhưng tại sao lại để ~ 5000 người dùng trực tuyến ngừng hoạt động vì lỗi nhỏ và dự đoán (lỗi vận hành)? điều ngược lại cũng không lý tưởng - giữ ứng dụng khi xảy ra sự cố không xác định (lỗi lập trình viên) có thể dẫn đến hành vi không lường trước được. Phân biệt cả hai cho phép hành động khéo léo và áp dụng cách tiếp cận cân bằng dựa trên bối cảnh nhất định
Mã ví dụ - làm đúng
//throwing an Error from typical function, whether sync or async
if(!productToAdd)
throw new Error("How can I add new product when no value provided?");
//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
//'throwing' an Error from a Promise
return new promise(function (resolve, reject) {
DAL.getProduct(productToAdd.id).then((existingProduct) =>{
if(existingProduct != null)
return reject(new Error("Why fooling us and trying to add an existing product?"));
ví dụ mã - đánh dấu một lỗi là hoạt động (đáng tin cậy)
//marking an error object as operational
var myError = new Error("How can I add new product when no value provided?");
myError.isOperational = true;
//or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
function appError(commonType, description, isOperational) {
Error.call(this);
Error.captureStackTrace(this);
this.commonType = commonType;
this.description = description;
this.isOperational = isOperational;
};
throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);
//error handling code within middleware
process.on('uncaughtException', function(error) {
if(!error.isOperational)
process.exit(1);
});
Blog trích dẫn : "Nếu không, bạn sẽ gặp rủi ro về trạng thái" (Từ blog có thể gỡ lỗi, xếp hạng 3 cho các từ khóa "Node.JS ngoại lệ không bị bắt")
"Về bản chất, cách ném hoạt động trong JavaScript, hầu như không có cách nào để nhận một cách an toàn trên mạng mà bạn rời khỏi, mà không bị rò rỉ tài liệu tham khảo hoặc tạo ra một số trạng thái giòn không xác định khác. Cách an toàn nhất để đáp ứng Một lỗi ném là làm tắt quá trình . Tất nhiên, trong một máy chủ web bình thường, bạn có thể có nhiều kết nối mở và không hợp lý khi tắt chúng đột ngột vì một lỗi khác được kích hoạt bởi người khác. gửi phản hồi lỗi đến yêu cầu gây ra lỗi, đồng thời để những người khác hoàn thành trong thời gian bình thường của họ và ngừng lắng nghe các yêu cầu mới trong nhân viên đó "
Số4: Xử lý lỗi tập trung, thông qua nhưng không nằm trong phần mềm trung gian
TL; DR: Lỗi xử lý logic như gửi thư đến quản trị viên và ghi nhật ký phải được gói gọn trong một đối tượng chuyên dụng và tập trung mà tất cả các điểm cuối (ví dụ: phần mềm trung gian Express, công việc định kỳ, kiểm tra đơn vị) gọi khi có lỗi xảy ra.
Mặt khác: Không xử lý lỗi trong một vị trí sẽ dẫn đến sao chép mã và có thể xảy ra lỗi được xử lý không đúng cách
Ví dụ mã - một luồng lỗi điển hình
//DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
if (error)
throw new Error("Great error explanation comes here", other useful parameters)
});
//API route code, we catch both sync and async errors and forward to the middleware
try {
customerService.addNew(req.body).then(function (result) {
res.status(200).json(result);
}).catch((error) => {
next(error)
});
}
catch (error) {
next(error);
}
//Error handling middleware, we delegate the handling to the centrzlied error handler
app.use(function (err, req, res, next) {
errorHandler.handleError(err).then((isOperationalError) => {
if (!isOperationalError)
next(err);
});
});
Trích dẫn trên blog: "Đôi khi các cấp thấp hơn không thể làm gì hữu ích ngoại trừ truyền lỗi cho người gọi của họ" (Từ blog Joyent, xếp hạng 1 cho các từ khóa Từ Node.JS xử lý lỗi lỗi)
"Tất cả các bạn có thể xử lý cùng một lỗi ở một số cấp độ của ngăn xếp. Điều này xảy ra khi các cấp thấp hơn không thể làm gì hữu ích ngoại trừ truyền lỗi cho người gọi của chúng, thông báo lỗi cho người gọi của nó, v.v. chỉ người gọi cấp cao nhất mới biết phản hồi phù hợp là gì, cho dù đó là thử lại thao tác, báo lỗi cho người dùng hay điều gì khác. Nhưng điều đó không có nghĩa là bạn nên cố gắng báo cáo tất cả các lỗi cho một cấp cao nhất gọi lại, vì chính cuộc gọi lại đó không thể biết lỗi xảy ra trong bối cảnh nào "
Số 5: Lỗi API tài liệu khi sử dụng Swagger
TL; DR: Hãy cho người gọi API của bạn biết lỗi nào có thể xảy ra để họ có thể xử lý những lỗi này một cách chu đáo mà không gặp sự cố. Điều này thường được thực hiện với các khung tài liệu API REST như Swagger
Mặt khác: Máy khách API có thể quyết định sự cố và chỉ khởi động lại vì anh ta đã nhận được lỗi mà anh ta không thể hiểu được. Lưu ý: người gọi API của bạn có thể là bạn (rất điển hình trong môi trường microservice)
Trích dẫn trên blog: "Bạn phải nói với người gọi của mình những lỗi nào có thể xảy ra" (Từ blog Joyent, xếp hạng 1 cho các từ khóa Nam Node.JS đăng nhập)
Mình đã nói về cách xử lý lỗi, nhưng khi bạn viết một hàm mới, làm thế nào để bạn chuyển lỗi đến mã được gọi là hàm của bạn? Nếu bạn không biết những lỗi nào có thể xảy ra hoặc không biết ý nghĩa của chúng, thì chương trình của bạn không thể chính xác trừ khi vô tình. Vì vậy, nếu bạn đang viết một chức năng mới, bạn phải nói với người gọi của bạn những lỗi nào có thể xảy ra và những gì họ có
Số 6: Đóng quy trình một cách duyên dáng khi có người lạ đến thị trấn
TL; DR: Khi xảy ra lỗi không xác định (lỗi nhà phát triển, xem phần thực hành tốt nhất số 3) - không chắc chắn về sức khỏe của ứng dụng. Một thực tiễn phổ biến đề nghị khởi động lại quá trình một cách cẩn thận bằng cách sử dụng công cụ 'restarter' như Mãi mãi và PM2
Mặt khác: Khi bị bắt ngoại lệ lạ, một số đối tượng có thể ở trạng thái bị lỗi (ví dụ: trình phát sự kiện được sử dụng trên toàn cầu và không kích hoạt sự kiện nữa do một số lỗi bên trong) và tất cả các yêu cầu trong tương lai có thể thất bại hoặc hành xử điên rồ
Ví dụ mã - quyết định xem có sụp đổ không
//deciding whether to crash when an uncaught exception arrives
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
process.on('uncaughtException', function(error) {
errorManagement.handler.handleError(error);
if(!errorManagement.handler.isTrustedError(error))
process.exit(1)
});
//centralized error handler encapsulates error-handling related logic
function errorHandler(){
this.handleError = function (error) {
return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
}
this.isTrustedError = function(error)
{
return error.isOperational;
}
Trích dẫn trên blog: "Có ba trường phái suy nghĩ về xử lý lỗi" (Từ blog jsrecipes)
Có rất nhiều trường phái suy nghĩ về xử lý lỗi: 1. Hãy để ứng dụng gặp sự cố và khởi động lại nó. 2. Xử lý tất cả các lỗi có thể và không bao giờ sụp đổ. 3. Cách tiếp cận cân bằng giữa hai
Số 7: Sử dụng trình ghi nhật ký trưởng thành để tăng khả năng hiển thị lỗi
TL; DR: Một tập hợp các công cụ ghi nhật ký trưởng thành như Winston, Bunyan hoặc Log4J, sẽ tăng tốc độ phát hiện và hiểu lỗi. Vì vậy, hãy quên console.log.
Mặt khác: Lướt qua console.logs hoặc thủ công qua tệp văn bản lộn xộn mà không có công cụ truy vấn hoặc trình xem nhật ký đàng hoàng có thể khiến bạn bận rộn đến công việc cho đến khuya
Mã ví dụ - Winston logger đang hoạt động
//your centralized logger object
var logger = new winston.Logger({
level: 'info',
transports: [
new (winston.transports.Console)(),
new (winston.transports.File)({ filename: 'somefile.log' })
]
});
//custom code somewhere using the logger
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });
Trích dẫn blog: "Hãy xác định một vài yêu cầu (đối với một trình ghi nhật ký):" (Từ blog strongblog)
Cho phép xác định một vài yêu cầu (đối với một logger): 1. Đóng dấu thời gian cho mỗi dòng nhật ký. Điều này là khá tự giải thích - bạn sẽ có thể nói khi mỗi mục nhập nhật ký xảy ra. 2. Định dạng ghi nhật ký nên dễ dàng tiêu hóa bởi con người cũng như máy móc. 3. Cho phép nhiều luồng đích cấu hình. Ví dụ: bạn có thể đang ghi nhật ký theo dõi vào một tệp nhưng khi gặp lỗi, hãy ghi vào cùng một tệp, sau đó vào tệp lỗi và gửi email cùng lúc
Số 8: Khám phá lỗi và thời gian chết khi sử dụng các sản phẩm APM
TL; DR: Các sản phẩm giám sát và hiệu suất (còn gọi là APM) chủ động đánh giá cơ sở mã hoặc API của bạn để chúng có thể tự động làm nổi bật các lỗi, sự cố và các phần chậm mà bạn đang thiếu
Mặt khác: Bạn có thể dành nhiều nỗ lực để đo hiệu suất và thời gian ngừng hoạt động của API, có lẽ bạn sẽ không bao giờ biết đâu là phần mã chậm nhất của bạn theo kịch bản trong thế giới thực và cách chúng ảnh hưởng đến UX
Trích dẫn blog: "Phân khúc sản phẩm APM" (Từ blog Yoni Goldberg)
"Các sản phẩm APM cấu thành 3 phân khúc chính: 1. Giám sát trang web hoặc API - các dịch vụ bên ngoài liên tục theo dõi thời gian hoạt động và hiệu suất thông qua các yêu cầu HTTP. Có thể được thiết lập trong vài phút. Sau đây là một vài ứng cử viên được chọn: Pingdom, Uptime Robot và New Relic
2 . Công cụ mã - họ sản phẩm cần nhúng một tác nhân trong ứng dụng để có lợi cho tính năng phát hiện mã chậm, thống kê ngoại lệ, giám sát hiệu suất và nhiều hơn nữa. Sau đây là một vài ứng cử viên được chọn: Relic mới, App Dynamics
3. Bảng điều khiển thông minh hoạt động -các dòng sản phẩm này được tập trung vào việc tạo điều kiện cho nhóm ops với các số liệu và nội dung được quản lý giúp dễ dàng đứng đầu về hiệu suất ứng dụng. Điều này thường liên quan đến việc tổng hợp nhiều nguồn thông tin (nhật ký ứng dụng, nhật ký DB, nhật ký máy chủ, v.v.) và công việc thiết kế bảng điều khiển trả trước. Sau đây là một vài ứng cử viên được chọn: Datadog, Splunk "
Trên đây là một phiên bản rút gọn - xem ở đây nhiều ví dụ và thực tiễn tốt nhất