await
Promise
を利用した非同期処理をより簡単に書ける構文としてasync
/await
が存在します。
この構文を利用することで、非同期処理をより同期処理と同じような文脈で書くことができるようになります。
async
/await
は基本セットで使いますが、本ページではawait
を主に取り上げます。
await
await
はPromise
の値が解決されるまで実行を待機して、解決された値を返します。
await
の注意点として基本的にawait
はasync
関数の中でしか使えません。
ts
// 1秒後に値を返すfunctionrequest ():Promise <string> {return newPromise ((resolve ) => {setTimeout (() => {resolve ("hello");}, 1000);});}// この書き方はできない// const result = await request();// console.log(result);async functionmain () {constresult = awaitrequest ();console .log (result );// @log: "hello"}main ();
ts
// 1秒後に値を返すfunctionrequest ():Promise <string> {return newPromise ((resolve ) => {setTimeout (() => {resolve ("hello");}, 1000);});}// この書き方はできない// const result = await request();// console.log(result);async functionmain () {constresult = awaitrequest ();console .log (result );// @log: "hello"}main ();
この例ではawait request()
の行でrequest()
がPromise
を解決するまで1秒待機し、コンソールに"hello"
と表示します。
async
/await
で書き直す
最後に3つのAPI呼び出しのコードをasync
/await
を利用して書き直してみます。
このようにasync
/await
を利用することで、非同期の処理を同期処理のようにスッキリ書くことができるようになります。
ts
// 非同期でAPIにリクエストを投げて値を取得する処理functionrequest1 ():Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (1);}, 1000);});}// 受け取った値を別のAPIにリクエストを投げて値を取得する処理functionrequest2 (result1 : number):Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (result1 + 1);}, 1000);});}// 受け取った値を別のAPIにリクエストを投げて値を取得する処理functionrequest3 (result2 : number):Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (result2 + 2);}, 1000);});}async functionmain () {constresult1 = awaitrequest1 ();constresult2 = awaitrequest2 (result1 );constresult3 = awaitrequest3 (result2 );console .log (result3 );// @log: 4}main ();
ts
// 非同期でAPIにリクエストを投げて値を取得する処理functionrequest1 ():Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (1);}, 1000);});}// 受け取った値を別のAPIにリクエストを投げて値を取得する処理functionrequest2 (result1 : number):Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (result1 + 1);}, 1000);});}// 受け取った値を別のAPIにリクエストを投げて値を取得する処理functionrequest3 (result2 : number):Promise <number> {return newPromise ((resolve ) => {setTimeout (() => {resolve (result2 + 2);}, 1000);});}async functionmain () {constresult1 = awaitrequest1 ();constresult2 = awaitrequest2 (result1 );constresult3 = awaitrequest3 (result2 );console .log (result3 );// @log: 4}main ();
Promise
を直接await
する
関数を作らずにPromise
を直接await
することもできます。
ts
async functionmain () {// 1秒後に値を返すawait newPromise ((resolve ) => {setTimeout (() =>resolve , 1000);});}
ts
async functionmain () {// 1秒後に値を返すawait newPromise ((resolve ) => {setTimeout (() =>resolve , 1000);});}
async
関数をawait
する
async
関数をawait
することもできます。
ts
async functionrequest ():Promise <string> {return "hello";}async functionmain () {constresult = awaitrequest ();console .log (result );// @log: "hello"}
ts
async functionrequest ():Promise <string> {return "hello";}async functionmain () {constresult = awaitrequest ();console .log (result );// @log: "hello"}
await
したときの型注釈
Promise
, async
関数の戻り値の型注釈はPromise<T>
のT
になります。
ts
async functionrequest ():Promise <string> {return "hello";}async functionmain () {constresult : string = awaitrequest ();// stringになるconsole .log (result );// @log: "hello"}
ts
async functionrequest ():Promise <string> {return "hello";}async functionmain () {constresult : string = awaitrequest ();// stringになるconsole .log (result );// @log: "hello"}
then-catch
をtry-catch
に書き換える
Promise
のthen
とcatch
をtry-catch
に書き換えることができます。次のmain2
関数はmain1
関数をtry-catch
で書き換えたものです。
ts
async functionrequest ():Promise <string> {return "hello";}functionmain1 () {request ().then ((result : string) => {console .log (result );// @log: "hello"}).catch ((error : unknown) => {console .log (error );});}async functionmain2 () {try {constresult : string = awaitrequest ();console .log (result );// @log: "hello"} catch (error : unknown) {console .log (error );}}
ts
async functionrequest ():Promise <string> {return "hello";}functionmain1 () {request ().then ((result : string) => {console .log (result );// @log: "hello"}).catch ((error : unknown) => {console .log (error );});}async functionmain2 () {try {constresult : string = awaitrequest ();console .log (result );// @log: "hello"} catch (error : unknown) {console .log (error );}}
拒否されたPromise
をreturn
するとき
return
の前にawait
する
拒否されたPromise
をreturn
する前にawait
したときは、その関数内で例外が発生します。
ts
async functionrequest ():Promise <unknown> {throw newError ("error");}async functionmain ():Promise <unknown> {try {// return await とすることでcatchで例外を捕捉できるreturn awaitrequest ();} catch {console .log ("error");// @log: error} finally {console .log ("finally");// @log: finally}}main ().then (() => {console .log ("then");// @log: then}).catch (() => {console .log ("catch");});
ts
async functionrequest ():Promise <unknown> {throw newError ("error");}async functionmain ():Promise <unknown> {try {// return await とすることでcatchで例外を捕捉できるreturn awaitrequest ();} catch {console .log ("error");// @log: error} finally {console .log ("finally");// @log: finally}}main ().then (() => {console .log ("then");// @log: then}).catch (() => {console .log ("catch");});
このような例であれば表示されるものはerror
とfinally
、そしてthen
が表示されます。
return
の前にawait
しない (ただreturn
する)
拒否されたPromise
をそのまま関数の戻り値にしてしまうと拒否されたまま呼び出し元に戻されます。
ts
functionrequest ():Promise <unknown> {throw newError ("error");}// try -> finally -> return -> catch()async functionmain ():Promise <unknown> {try {returnrequest ();} catch {console .log ("error");} finally {console .log ("finally");// @log: finally}}main ().then (() => {console .log ("then");}).catch (() => {console .log ("catch");// @log: catch});
ts
functionrequest ():Promise <unknown> {throw newError ("error");}// try -> finally -> return -> catch()async functionmain ():Promise <unknown> {try {returnrequest ();} catch {console .log ("error");} finally {console .log ("finally");// @log: finally}}main ().then (() => {console .log ("then");}).catch (() => {console .log ("catch");// @log: catch});
このような例であれば表示されるものはfinally
とcatch
が表示されます。