私は非同期/待機を続けてきました、そしていくつかの記事を調べた後、私は自分自身でテストすることにしました。しかし、これがうまくいかないのは、頭を包むようには思えません。
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = main();
console.log('outside: ' + text)
コンソールは次のように出力します(ノードv8.6.0)。
> outside:[オブジェクトの約束]
> inside:ちょっとそこ
関数内のログメッセージが後で実行されるのはなぜですか。 async/awaitが作成された理由は、非同期タスクを使用して同期実行を実行するためであると思いました。
.then()
の後にmain()
を使わずに関数内で返された値を使う方法はありますか?
これがうまくいかないのは、頭を包むようには思えない。
なぜならmain
は約束を返すからです。すべてのasync
関数が行います。
最上位レベルでは、次のいずれかを行う必要があります。
拒否しないような最上位のasync
関数を使用します( "未処理の拒否"エラーが発生しない限り)。
then
およびcatch
を使用する
(近日公開予定)最上位レベルのawait
を使用します。これは、ステージ3に到達したという提案です。 process では、モジュール内でawait
をトップレベルで使用できます。
async
関数(async () => {
try {
var text = await main();
console.log(text);
} catch (e) {
// Deal with the fact the chain failed
}
})();
catch
に注意してください。あなたは約束の拒否/非同期例外を扱わなければならない。あなたに渡すための呼び出し元はいません。お望みであれば、(catch
/try
構文ではなく)catch
関数を介してそれを呼び出した結果でそれを行うことができます。
(async () => {
var text = await main();
console.log(text);
})().catch(e => {
// Deal with the fact the chain failed
});
...これはもう少し簡潔です(私はその理由でそれが好きです)。
または、もちろん、エラーを処理せず、単に「未処理の拒否」エラーを許可します。
then
とcatch
main()
.then(text => {
console.log(text);
})
.catch(err => {
// Deal with the fact the chain failed
});
チェーン内またはcatch
ハンドラ内でエラーが発生した場合は、then
ハンドラが呼び出されます。 (catch
ハンドラはエラーを処理するためのものが何も登録されていないため、エラーをスローしないようにしてください。)
あるいはthen
への両方の引数:
main().then(
text => {
console.log(text);
},
err => {
// Deal with the fact the chain failed
}
);
再度、拒否ハンドラを登録しています。しかしこの形式では、あなたのthen
コールバックのいずれもエラーをスローしないこと、それらを処理するための登録がないことを確認してください。
await
非モジュールスクリプトのトップレベルでawait
を使用することはできませんが、トップレベルのawait
プロポーザルでは、モジュールのトップレベルでそれを使用できます。トップレベルのコードを拒否(エラーをスロー)させたくないという点で、トップレベルのasync
関数ラッパー(上記の#1)を使用するのと同じことが、未処理の拒否エラーが発生するためです。そのため、#1のように、問題が発生したときに未処理の拒否を行わないようにするには、コードをエラーハンドラでラップする必要があります。
// In a module, once the top-level `await` proposal lands
try {
var text = await main();
console.log(text);
} catch (e) {
// Deal with the fact the chain failed
}
トップレベルawait
がステージ3に移動したため、質問への回答トップレベルでasync/awaitを使用するにはどうすればよいですか?await
への呼び出しをmain()
に追加するだけです:
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = await main();
console.log('outside: ' + text)
あるいは単に:
const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)
[email protected] でのみ利用可能であることに注意してください。
この問題に対する実際の解決策は、それとは異なる方法で対処することです。
おそらくあなたの目標は、通常アプリケーションのトップレベルで行われるある種の初期化です。
解決策は、アプリケーションのトップレベルにJavaScriptステートメントが1つだけ存在するようにすることです。アプリケーションの先頭に文が1つしかない場合は、どこにでもasync/awaitを自由に使用できます(もちろん通常の構文規則による)。
別の言い方をすると、最上位レベルがもう最上位レベルではなくなり、アプリケーションの最上位レベルでasync/waitを実行する方法の問題を解決するように、最上位レベル全体を関数でラップするということです。
これがあなたのアプリケーションのトップレベルがどのように見えるべきかということです:
import {application} from './server'
application();
現在の答えの上にいくつかのさらなる情報を与えるために:
node.js
ファイルの内容は、現在、文字列のように連結されて関数本体を形成しています。
たとえばtest.js
というファイルがあるとします。
// Amazing test file!
console.log('Test!');
node.js
は密かに以下のような関数を連結します。
function(require, __dirname, ... a bunch more top-level properties) {
// Amazing test file!
console.log('test!');
}
注意すべき重要な点は、結果として得られる関数は非同期関数ではないということです。そのため、await
という用語を直接その中に使用することはできません。
しかし、このファイルでプロミスを扱う必要があるとしたら、2つの方法があります。
await
直接を使用しないawait
を使用しないオプション1では、新しいスコープを作成する必要があります(これを制御できるので、このスコープをasync
にすることができます)。
// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
await new Promise(...);
console.log('Test!');
})();
オプション2では、オブジェクト指向のpromise APIを使用する必要があります(promiseを扱う際の、あまり機能的ではありませんが、機能的なパラダイム)
// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);
// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));
実行可能であれば、node.jsがデフォルトでコードをasync
関数に連結することを私は個人的に願っています。それはこの頭痛を取り除きます。
main()
は非同期的に実行されるので、約束を返します。あなたはthen()
メソッドで結果を得なければなりません。 then()
もpromiseを返すので、プログラムを終了するにはprocess.exit()
を呼び出さなければなりません。
main()
.then(
(text) => { console.log('outside: ' + text) },
(err) => { console.log(err) }
)
.then(() => { process.exit() } )