63
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Async Await in Typescript

Posted at

はじめに

最近、Typescirptを使い始めた若輩者ですが、もう型がないと息ができないくらいTypescriptに嵌まってしまいました。
今回はTypescriptの機能の一つであるAsync/Awaitを紹介します。

ES6にはPromiseがあり、非同期処理が非常に簡単に書けるようになりました。
しかし、ECMAScriptはさらなる高みを目指しているみたいです。
より発展的に非同期処理を記述できるようにするために、Async/Awaitを提案し、すでにstage3に入ってきています。

Babelでは、babel-preset-es2017 もしくは babel-plugin-transform-async-to-generatorを利用することで使用することができるみたいです。

ECMAScriptのSupersetであるTypescriptも、Async/Awaitをサポートしています。(v1.6~)

Promiseによって、充分、非同期処理が簡単に書けるのですが、
Async/Awaitはさらに簡略で、より慣れた手続き的な書き方で書けるようになります。

動作環境

Typescript v2.1.4

Async/Awaitのサポート

今までは compilerOptionsの target を es6 に指定しないと、typescriptでAsync/Awaitをコンパイルできませんでした。
そのため、ブラウザ環境向けに利用するには、TypescirptからES6にコンパイルして、さらにBabelでトランスパイルするような過程が必要だったりしたですが、v2.1より es5/es3に指定してもコンパイルできるようになりました。
これにより、より気軽にAsync/Awaitが使えるようになりましたね。

What's New TypeScript 2.1

v1.6から --experimentalAsyncFunctionsオプション付きでサポートを開始
v1.7からオプションなし、"target": "es6" 限定でサポート
v2.1から "target": "es5/es3"でサポート

使ってみる

2秒間待ってから "wait" と出力するwait関数を3回直列で実行するサンプルを書いてみます。

まず、Promiseで書いてみます。

promise.ts
// Promiseを返す非同期関数
function wait(): Promise<any> {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('wait');
    }, 2000);
  })
}

function main() {
  return wait()
    .then(() => {
      return wait();
    })
    .then(() => {
      return wait();
    });
}

main();

コールバックを用いた書き方よりはだいぶいいのですが、returnが多かったり、何度もthenをして、少し冗長な気がします。
上記のmain関数をAsync/Awaitを用いた書き方で書き直してみます。

async.ts

// functionの前にasyncを書くとasync関数になります。
async function main() {
  await wait();
  await wait();
  await wait();
}

main();


.then()もなく、かなりスッキリした書き方になりました。

このように、Async関数の中でPromiseを返す関数の前にawaitをつけるとその関数の処理が終わるまで待ってくれます。

Async/Awaitはこのようなシンプルな記述をだけでなく、Promiseでは難しいより慣れた手続き的な表現ができます。

Promiseでは処理の結果をresolve()でPromiseに包んで.then()のコールバック関数の引数として次の処理につなげることができますが、Async/Awaitを使えば、あたかも同期関数のように = で代入するような記述ができます。

//42がラップされたPromiseを返す関数
function foo() {
  return Promise.resolve(42);
}


function main() {
  foo().then(num => {
    console.log(num); //=> 42
  });
}
main();

async function main2() {
  // あたかも普通の同期関数のように = で代入できる
  const num = await foo();
  console.log(num); //=> 42

  // ちなみに型推論もちゃんとやってくれる
  typeof(num) === 'number' //=> true
}

main2();

また、Promiseでのチェーンでは途中で処理を終了したい時などには.reject()して.catch()するなど工夫が必要です。

しかし、Async/Awaitならば、通常の手続き処理のようにif文やswitch文、変数代入に利用できるので、自在に処理を切り分けたり、中断させることができます。


async function foo() {
  // if文で使ったり
  if (await model.exists()) {
  
  }
  // そのまま関数に渡したり
  bar(await foo());

  // 返り値の配列をそのまま参照
  let result = (await bar())[0]
}

async関数はそれ自体が何もしなくても自動的にPromiseを返すので、async関数の実行に続けて、.then()かawaitを書くことができます。


// Promiseを返すasync関数
async foo() {
  return wait();
}

// .then()で続ける
foo().then(() => {
   foo();
});

// awaitで待つ
async main() {
  await foo();
}


いかがでしょうか。
その他、Async/Awaitは様々なパターンの関数やメソッドに利用できます。


// アロー関数をAsync関数化
async () => {
  await this.foo();
}


// クラスのメソッドにもasyncが書ける
class Foo {

  async bar() {
    await this.wait();
  }

  static async bar() {
    await wait();
  }
}



とてつもなく簡単に非同期処理が書けるので、気持ちよくコードを書くことができます。

ぜひ使ってみてください。

参考
公式ドキュメント
JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版

63
49
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?