Adalah adil untuk mengatakan bahwa janji hanyalah gula sintaksis. Segala sesuatu yang dapat Anda lakukan dengan janji yang dapat Anda lakukan dengan panggilan balik. Bahkan, sebagian besar implementasi janji memberikan cara untuk mengkonversi antara keduanya kapan pun Anda inginkan.
Alasan mendalam mengapa janji sering kali lebih baik adalah bahwa mereka lebih tenang , yang secara kasar berarti bahwa menggabungkan beberapa janji "hanya berfungsi", sementara menggabungkan beberapa panggilan balik sering kali tidak. Sebagai contoh, itu sepele untuk menetapkan janji ke variabel dan melampirkan penangan tambahan untuk nanti, atau bahkan melampirkan penangan ke sekelompok besar janji yang dieksekusi hanya setelah semua janji selesai. Meskipun Anda dapat mengemulasi hal-hal ini dengan callback, dibutuhkan lebih banyak kode, sangat sulit untuk dilakukan dengan benar, dan hasil akhirnya biasanya jauh lebih tidak dapat dipertahankan.
Salah satu cara terbesar (dan paling halus) yang dijanjikan mendapatkan kompabilitas mereka adalah dengan penanganan nilai pengembalian yang sama dan pengecualian yang tidak tertangkap. Dengan panggilan balik, bagaimana pengecualian ditangani mungkin sepenuhnya bergantung pada mana dari banyak panggilan balik bersarang yang melemparkannya, dan fungsi mana yang menerima panggilan balik yang memiliki coba / tangkap dalam implementasinya. Dengan janji, Anda tahu bahwa pengecualian yang lolos dari satu fungsi panggilan balik akan ditangkap dan diteruskan ke penangan kesalahan yang Anda berikan .error()
atau .catch()
.
Misalnya, Anda memberikan satu panggilan balik versus satu janji, memang benar tidak ada perbedaan yang signifikan. Justru ketika Anda memiliki miliaran panggilan balik versus satu miliar janji, kode berbasis janji cenderung terlihat jauh lebih baik.
Berikut adalah upaya pada beberapa kode hipotetis yang ditulis dengan janji dan kemudian dengan panggilan balik yang seharusnya cukup kompleks untuk memberi Anda beberapa gagasan tentang apa yang saya bicarakan.
Dengan Janji:
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);
}
Dengan Callback:
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);
}
});
});
});
}
Mungkin ada beberapa cara pintar untuk mengurangi duplikasi kode dalam versi callback bahkan tanpa janji, tetapi semua yang saya bisa pikirkan untuk menerapkan sesuatu yang sangat menjanjikan.