Công bằng mà nói lời hứa chỉ là cú pháp đường. Tất cả mọi thứ bạn có thể làm với lời hứa bạn có thể làm với các cuộc gọi lại. Trong thực tế, hầu hết các triển khai hứa hẹn cung cấp các cách chuyển đổi giữa hai bất cứ khi nào bạn muốn.
Lý do sâu tại sao lời hứa thường tốt hơn là họ có nhiều composeable , mà có nghĩa là khoảng cách kết hợp nhiều lời hứa "chỉ hoạt động", trong khi cách kết hợp nhiều callbacks thường thì không. Chẳng hạn, việc gán lời hứa cho một biến và đính kèm các trình xử lý bổ sung cho nó sau này, hoặc thậm chí đính kèm một trình xử lý vào một nhóm lớn các lời hứa chỉ được thực hiện sau khi tất cả các lời hứa được giải quyết. Mặc dù bạn có thể sắp xếp mô phỏng những thứ này bằng các cuộc gọi lại, nhưng nó đòi hỏi nhiều mã hơn, rất khó để thực hiện chính xác và kết quả cuối cùng thường ít được duy trì hơn nhiều.
Một trong những cách lớn nhất (và tinh vi nhất) hứa hẹn đạt được khả năng kết hợp của chúng là bằng cách xử lý thống nhất các giá trị trả về và các ngoại lệ chưa được lưu. Với các cuộc gọi lại, làm thế nào một ngoại lệ được xử lý có thể phụ thuộc hoàn toàn vào việc trong số nhiều cuộc gọi lại lồng nhau đã ném nó và chức năng nào thực hiện cuộc gọi lại có một thử / bắt trong quá trình thực hiện. Với lời hứa, bạn biết rằng một ngoại lệ thoát khỏi một hàm gọi lại sẽ bị bắt và chuyển đến bộ xử lý lỗi mà bạn cung cấp .error()
hoặc .catch()
.
Đối với ví dụ bạn đã đưa ra một cuộc gọi lại so với một lời hứa duy nhất, thì đúng là không có sự khác biệt đáng kể nào. Đó là khi bạn có một cuộc gọi lại hàng tỷ so với một tỷ lời hứa rằng mã dựa trên lời hứa có xu hướng trông đẹp hơn nhiều.
Đây là một nỗ lực đối với một số mã giả định được viết bằng lời hứa và sau đó với các cuộc gọi lại chỉ đủ phức tạp để cung cấp cho bạn một số ý tưởng về những gì tôi đang nói.
Với những lời hứa:
createViewFilePage(fileDescriptor) {
getCurrentUser().then(function(user) {
return isUserAuthorizedFor(user.id, VIEW_RESOURCE, fileDescriptor.id);
}).then(function(isAuthorized) {
if(!isAuthorized) {
throw new Error('User not authorized to view this resource.'); // gets handled by the catch() at the end
}
return Promise.all([
loadUserFile(fileDescriptor.id),
getFileDownloadCount(fileDescriptor.id),
getCommentsOnFile(fileDescriptor.id),
]);
}).then(function(fileData) {
var fileContents = fileData[0];
var fileDownloads = fileData[1];
var fileComments = fileData[2];
fileTextAreaWidget.text = fileContents.toString();
commentsTextAreaWidget.text = fileComments.map(function(c) { return c.toString(); }).join('\n');
downloadCounter.value = fileDownloads;
if(fileDownloads > 100 || fileComments.length > 10) {
hotnessIndicator.visible = true;
}
}).catch(showAndLogErrorMessage);
}
Với cuộc gọi lại:
createViewFilePage(fileDescriptor) {
setupWidgets(fileContents, fileDownloads, fileComments) {
fileTextAreaWidget.text = fileContents.toString();
commentsTextAreaWidget.text = fileComments.map(function(c) { return c.toString(); }).join('\n');
downloadCounter.value = fileDownloads;
if(fileDownloads > 100 || fileComments.length > 10) {
hotnessIndicator.visible = true;
}
}
getCurrentUser(function(error, user) {
if(error) { showAndLogErrorMessage(error); return; }
isUserAuthorizedFor(user.id, VIEW_RESOURCE, fileDescriptor.id, function(error, isAuthorized) {
if(error) { showAndLogErrorMessage(error); return; }
if(!isAuthorized) {
throw new Error('User not authorized to view this resource.'); // gets silently ignored, maybe?
}
var fileContents, fileDownloads, fileComments;
loadUserFile(fileDescriptor.id, function(error, result) {
if(error) { showAndLogErrorMessage(error); return; }
fileContents = result;
if(!!fileContents && !!fileDownloads && !!fileComments) {
setupWidgets(fileContents, fileDownloads, fileComments);
}
});
getFileDownloadCount(fileDescriptor.id, function(error, result) {
if(error) { showAndLogErrorMessage(error); return; }
fileDownloads = result;
if(!!fileContents && !!fileDownloads && !!fileComments) {
setupWidgets(fileContents, fileDownloads, fileComments);
}
});
getCommentsOnFile(fileDescriptor.id, function(error, result) {
if(error) { showAndLogErrorMessage(error); return; }
fileComments = result;
if(!!fileContents && !!fileDownloads && !!fileComments) {
setupWidgets(fileContents, fileDownloads, fileComments);
}
});
});
});
}
Có thể có một số cách thông minh để giảm trùng lặp mã trong phiên bản gọi lại ngay cả khi không có lời hứa, nhưng tất cả những cách tôi có thể nghĩ đến để thực hiện một cái gì đó rất giống như lời hứa.