câu chuyện ngắn:Làm thế nào để từ chối (và sử dụng đúng) Lời hứa?
Nói về Promises/A +, cách thích hợp để từ chối một lời hứa là gì - ném một lỗi? Nhưng nếu tôi bỏ lỡ
catch
- toàn bộ ứng dụng của tôi sẽ thổi!Cách sử dụng
promisify
và lợi ích của nó (có thể bạn sẽ cần phải đọc phiên bản dài hơn)?Có phải
.then(success, fail)
thực sự là anti-pattern và tôi có nên luôn sử dụng.then(success).catch(error)
không?
dài hơn phiên bản, được mô tả như vấn đề thực tế đời sống (sẽ yêu một ai đó để đọc):
Tôi đã một thư viện có sử dụng Bluebird (A + Promise thư viện thực hiện), để lấy dữ liệu từ cơ sở dữ liệu (nói khoảng Sequelize). Mỗi truy vấn trả về một kết quả, nhưng đôi khi nó trống (cố gắng chọn một cái gì đó, nhưng không có bất kỳ). Lời hứa đi vào chức năng result
, vì không có lý do gì cho lỗi (không có kết quả không phải là lỗi). Ví dụ:
Entity.find(1).then(function(result) {
// always ending here, despite result is {}
}).catch(function(error) {
// never ends here
});
Tôi muốn bọc phần này và kiểm tra xem kết quả có trống không (không thể kiểm tra điều này ở mọi nơi trong mã của tôi). Tôi đã làm điều này:
function findFirst() {
return Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
return result; // will invoke the success function
} else {
// I WANT TO INVOKE THE ERROR, HOW?! :)
}
}).catch(function(error) {
// never ends here
});
}
findFirst().then(function(result) {
// I HAVE a result
}).catch(function(error) {
// ERROR function - there's either sql error OR there is no result!
});
Nếu bạn vẫn ở bên tôi - tôi hy vọng bạn sẽ hiểu điều gì đang xảy ra. Tôi muốn bằng cách nào đó để cháy lên các chức năng lỗi (nơi "ERROR chức năng" là). Vấn đề là - tôi không biết làm thế nào. Tôi đã thử những điều sau:
this.reject('reason'); // doesn't work, this is not a promise, Sequelize related
return new Error('reason'); // calls success function, with error argument
return false; // calls success function with false argument
throw new Error('reason'); // works, but if .catch is missing => BLOW!
Như bạn có thể thấy bằng nhận xét của tôi (và mỗi thông số), việc ném lỗi hoạt động tốt. Tuy nhiên, có một số lớn nhưng - nếu tôi bỏ lỡ câu lệnh .catch
, toàn bộ ứng dụng của tôi sẽ phát sinh.
Tại sao tôi không muốn điều này? Giả sử tôi muốn tăng bộ đếm trong cơ sở dữ liệu của mình. Tôi không quan tâm đến kết quả - tôi chỉ yêu cầu HTTP .. Vì vậy, tôi có thể gọi incrementInDB()
, có khả năng trả về kết quả (ngay cả đối với lý do kiểm tra), vì vậy có throw new Error
nếu không thành công. Nhưng vì tôi không quan tâm đến phản hồi, đôi khi tôi sẽ không thêm câu lệnh .catch, phải không? Nhưng bây giờ - nếu tôi không (về mục đích hoặc do lỗi) - tôi kết thúc với ứng dụng nút của bạn xuống.
Tôi không tìm thấy điều này rất đẹp. Có cách nào tốt hơn cách để làm việc đó hoặc tôi chỉ phải giải quyết nó?
Một người bạn của tôi đã giúp tôi ra và tôi đã sử dụng một lời hứa mới để sửa chữa mọi thứ lên, như thế này:
function findFirst() {
var deferred = new Promise.pending(); // doesnt' matter if it's Bluebird or Q, just defer
Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
deferred.resolve(result);
} else {
deferred.reject('no result');
}
}).catch(function(error) {
deferred.reject('mysql error');
);
return deferred.promise; // return a promise, no matter of framework
}
trình như một say mê! Nhưng Tôi đã nhận được điều này: Promise Anti Patterns - bài viết wiki được viết bởi Petka Antonov, tác giả của Bluebird (A + triển khai). Rõ ràng là đây là sai.
Câu hỏi thứ hai của tôi là - có phải vậy không? Nếu đúng thì tại sao? Và cách tốt nhất là gì?
Cảm ơn rất nhiều vì đã đọc bài này, tôi hy vọng ai đó sẽ dành thời gian để trả lời cho tôi :) Tôi nên thêm rằng tôi không muốn phụ thuộc quá nhiều vào khung công tác, vì vậy Sequelize
và Bluebird
chỉ là những thứ tôi đã kết thúc làm việc với. Vấn đề của tôi là với Promises như một toàn cầu, không phải với các khung công tác đặc biệt này.
Để 'Nhưng, có một lớn nhưng - nếu tôi bỏ lỡ tuyên bố .catch, toàn bộ ứng dụng của tôi thổi lên.' không phải là những gì ngoại lệ là về? Bạn nên luôn luôn xử lý ngoại lệ, ngay cả khi bạn không quan tâm đến sự thất bại, bạn nên làm cho rõ ràng trong mã bằng cách thêm một '.catch' với một nhận xét mà bạn không quan tâm về nó. Hãy tưởng tượng bạn sẽ xem lại mã của bạn một lần nữa và nhận ra rằng có một ngoại lệ không được chấp nhận nhưng bạn không nhớ tại sao nó lại không được giải quyết, sau đó bạn sẽ dành nhiều thời gian để xác định lý do. –
Đó là về năng suất, làm việc với nhiều nhà phát triển và không phải ở độ tin cậy cuối cùng. Nó dễ dàng hơn cho bất kỳ dev nào để viết 'incrementInDB(); 'hơn là lướt mã, đọc đây là lời hứa sẽ báo lỗi, vì vậy bạn ** phải bắt nó.Như tôi đã nói - Tôi không muốn ngoại lệ - tôi chỉ không thể tìm ra cách khác để làm điều đó mà không làm nổ tung toàn bộ ứng dụng của tôi :) –
Tôi nghĩ nhận xét của t.niese phải là câu trả lời. Có, nó có thể được * dễ dàng hơn * cho bất kỳ dev để viết một dòng mã hơn để viết * mã * thích hợp, nhưng đó không phải là lý do. Cách quá thường xuyên tôi thấy mã từ các nhà phát triển thiếu kinh nghiệm, nơi ngoại lệ được ném từ một số API được âm thầm nuốt và chuyển đổi để trở về null vv Một số nhà phát triển dường như có một số loại sợ hãi cơ bản của trường hợp ngoại lệ. Với việc sử dụng đúng cách catch() và thực hiện() Tôi thực sự không thấy bất kỳ vấn đề nào. Bên cạnh đó, bạn luôn có thể viết xử lý ngoại lệ không bị bắt buộc của riêng mình nếu cần? – JHH