ようこそコールバック地獄です。 :-)古い "Node"のやり方はネストされたコールバックを行うことであり、非常に醜いです。
現代的なアプローチは、複数の非同期操作を一緒に構成することを容易にする約束を使用することです。独自の非同期関数が約束を返すようにし、ノードAPI関数(または約束をまだ提供していないアドオンライブラリ)については、ラッパーを使用してそれらを約束できるようにします(手動またはpromisify
のようなものを使用します)。約束ベースの機能を備えた
は、例えば、あなたの呼び出しは次のようになります。
app.get('/',function(req,res){
readFilePromise('client_secret.json')
.then(content => JSON.parse(content))
.then(authorise)
.then(findFiles)
.then(files => {
res.render('index', files);
})
.catch(err => {
// Render error here
});
});
またはJSON.parse
もfindFiles
でもないので、非同期です:
app.get('/',function(req,res){
readFilePromise('client_secret.json')
.then(content => authorise(JSON.parse(content)))
.then(auth => {
res.render('index', findFiles(auth));
})
.catch(err => {
// Render error here
});
});
それは非非同期を使用するように罰金です関数がthen
であれば、関数は1つのパラメータを期待して処理された結果を返すので、最初のバージョンも正常です。ビット頭がかかわった。 (また —主観性の警告に注意し —ことを、我々は終わっていないので、
function authorise(credentials) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
return readFilePromise(TOKEN_PATH)
.then(token => {
oauth2Client.credentials = JSON.parse(token);
return oauth2Client;
});
}
:!両方のケースで
、readFilePromise
はreadFile
のpromisifiedバージョンで、authorize
はこのような何かに見えます地獄の深くネストされたコールバック構造では、2つのスペースではなく合理的なインデント幅を使用できるため、多くのNodeプログラマが採用する必要があると感じていました)
さらにノードV8を使用している場合はさらに進みます。
app.get('/', async function(req, res){
try {
const credentials = JSON.parse(await readFilePromise('client_secret.json'));
const auth = await authorize(credentials);
const files = findFiles(auth);
res.render('index', files);
} catch (e) {
// Render error here
}
});
は注意function
とawait
前async
私たちは約束を返す関数を呼び出している任意の時間を:X +、あなたはそれらの約束を消費するasync
/await
構文を使用することができます。 async
関数は、カバーの下に約束を返し、await
はカバーの下で約束を消費します。コードはと同期していますが、そうではありません。 await
は、事実上、約束が完了したときにコールバックを登録するthen
への呼び出しです。同様に、try
/catch
は、事実上、約束チェーン上のcatch
メソッドへの呼び出しです。
我々は我々が望んでいた場合、その凝縮できます
app.get('/', async function(req, res){
try {
res.render('index', findFiles(await authorize(JSON.parse(await readFilePromise('client_secret.json'))));
} catch (e) {
// Render error here
}
});
...しかし、読みやすさ/ debuggabilityが苦しみます。 :-)
重要な注意:約束を返すために機能を期待されていないこと(app.get
のような)何かにasync
機能を渡すとき、あなたは上記のようtry
/catch
でそれをラップし、すべてのエラーを処理する必要がありますなぜなら、呼び出しコードが約束を期待していなければ、それは約束の拒否を処理しないので、それを行う必要があるからです。未処理の拒否は悪いことです(そして、Nodeの将来のバージョンでは、プロセスが終了することになります)。
あなたはにasync
機能を渡しているものならばはtry/
catch`をオフのままにしてエラーが伝播することを可能にするために、プロセスを返す関数を期待する最高ありません。
あなたはfindFiles
のヘルプを求めました。私はpromisify
かそれと似たようなことを学ぶことをお勧めします。これを解決する正しい方法は、drive.files.list
という有名なバージョンを提供することです。drive.files.list
は代わりにノードスタイルのコールバックを使用するためです。
しかし、それをpromisifyingせずに、私たちはこれを行うことができます:
function findFiles(auth) {
var drive = google.drive('v3');
return new Promise(function(resolve, reject) {
drive.files.list({
auth: auth,
folderId: '****************',
q: "mimeType contains 'application/pdf' and trashed = false"
},
function(err, response) {
if (err) {
reject(err);
return;
}
var f = response.files;
if (f.length == 0) {
console.log('No files found.');
}
else {
var key = 'files'; // Why this indirection??
resolve({[key]: f.map(file => file.name + ' ' + file.id)});
// Without the indirection it would be:
// resolve({files: f.map(file => file.name + ' ' + file.id)});
}
});
});
}
我々はpromisifiedバージョンを持っていた、と私たちは不要と思われるkey
間接に離れていた場合、それは単純に次のようになります。
function findFiles(auth) {
return drivePromisified.files.list({
auth: auth,
folderId: '****************',
q: "mimeType contains 'application/pdf' and trashed = false"
}).then(files => ({files: files.map(file => file.name + ' ' + file.id)}));
}
それともasync
関数としてawait
使用:
async function findFiles(auth) {
const files = await drivePromisified.files.list({
auth: auth,
folderId: '****************',
q: "mimeType contains 'application/pdf' and trashed = false"
});
return {files: files.map(file => file.name + ' ' + file.id)};
}
コントロールはreadFileに達し、次にAuthorizeに行きます(私はauthorizeによって返されたオブジェクトをログに記録できますが、それ以降はエラーをキャッチします)。 : – AlwaysHungrie