約束は単なる構文上の砂糖であると言ってもいいでしょう。コールバックでできる約束でできることはすべて。実際、ほとんどのプロミス実装は、必要に応じて2つの間で変換する方法を提供します。
約束がしばしば良い理由は、それらがより構成可能だということです。これは、複数の約束を組み合わせると「うまくいく」ことを意味しますが、複数のコールバックを組み合わせることはしばしばそうではないことを意味します。たとえば、promiseを変数に割り当てて、後で追加のハンドラーを追加したり、すべてのpromiseが解決した後にのみ実行される大きなグループのpromiseにハンドラーを追加したりするのは簡単です。コールバックを使用してこれらのことをエミュレートすることはできますが、多くのコードが必要になり、正しく実行するのが非常に難しく、最終結果の保守性がはるかに低くなります。
約束が構成可能になる最大の(そして最も微妙な)方法の1つは、戻り値とキャッチされない例外の均一な処理です。コールバックでは、多くのネストされたコールバックのどれが例外をスローしたか、コールバックを取得する関数のどれがその実装にtry / catchを持っているかに完全に依存します。promiseを使用すると、1つのコールバック関数をエスケープする例外がキャッチされ、またはで指定したエラーハンドラーに渡されることがわかります。.error()
.catch()
単一のコールバックと単一のプロミスを指定した例では、大きな違いはありません。無数の約束に対して無数のコールバックがある場合、約束ベースのコードはより良く見える傾向があります。
ここで、promiseを使用して記述された仮想コードと、次に説明するコールバックを使用して、私が話していることを理解できるようにするための複雑なコードを試みます。
約束あり:
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);
}
コールバックあり:
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);
}
});
});
});
}
コールバックバージョンでは、約束がなくてもコードの重複を減らす賢い方法があるかもしれませんが、私が考えることができるものはすべて、非常に約束のようなものを実装することに要約できます。