Help us understand the problem. What is going on with this article?

ES7 の Async/Await を使ってみた

More than 5 years have passed since last update.

Taming the asynchronous beast with ES7

babel の experimental に ES7 の Async/Await が入ったというので、さっそく導入してみた。対象は画像を点字を変換するわりかしどうでも良いモジュール。

導入前

ファイル読み込みや画像の変換に非同期処理を多用しており、node.js スタイルの 非同期API(コールバックを渡すやつ) を prominence というユーティリティ関数で Promise 化していたが、行ごとに then が出てきたり、複数の値を渡すために Promise.all を使ったりと、あまり読みやすいとは言えないコードだった。(コールバック地獄になるよりはマシだと思うけど..)

convert.js
import gm from "gm";
import pngparse from "pngparse";

// 画像を点字に変換する
let convert = (src, opts) => {
  // 画像を GraphicsMagick の形式に変換
  return Promise.resolve(gm(src)).then((im) => {
    // サイズを取得
    return Promise.all([ im, prominence(im).size() ]);
  }).then(([ im, size ]) => {
    // 画像を加工 (省略)
    return im;
  }).then((im) => {
    // PNGに変換
    return prominence(im).toBuffer("png");
  }).then((buffer) => {
    // PNGをパース
    return prominence(pngparse).parse(buffer);
  }).then((png) => {
    // PNGを点字に変換 (省略)
    return "点字";
  });
};

導入準備

まず babel をアップデートして、devDependencies から dependencies に移動。

package.json
"dependencies": {
    "babel": "^4.7.8"
}

.babelrc で ES7 機能を使うフラグを設定。

.babelrc
{
  "experimental": true
}

async/await を使うファイルで babel/polyfill をインポートする。これがないと実行時に "regeneratorRuntime is not defined" というエラーが出る。

import "babel/polyfill";

導入後

await を使う関数自体を async function にして、非同期処理を行う関数呼び出しに await を追加するだけ。手続き型言語!!という感じで、コードの見通しは非常に良くなったと思う。使う側のコードに変更は不要で、書き換える前と同じインターフェース(この場合はPromise)で使える。

convert.js
import gm from "gm";
import pngparse from "pngparse";

// 画像を点字に変換する
export async function convert(src, opts) {
  // 画像を GraphicsMagick の形式に変換
  let im = gm(src);

  // サイズを取得
  let size = await prominence(im).size();

  // 画像を加工 (省略)

  // PNGに変換
  let buffer = await prominence(im).toBuffer("png");

  // PNGをパース
  let png = await prominence(pngparse).parse(buffer);

  // PNGを点字に変換 (省略)
  return "点字";
};

知見

事前にPromise化していた効果が大きかったのか、コードの書き換えはあっという間にできた。最近 Promise がいまいち使いづらいと思い始めていたけど、使い続けるモチベーションにはなった。

失ったもの

  • lint (jshint) が使えなくなったので消した

diff

https://github.com/mohayonao/seurat/commit/dc84628ac0a3fc546b6e93259388f3751d014dcd

mohayonao
友達がいないひと。JavaScriptで音だして遊んだりする。
https://mohayonao.github.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした