【初心者向き】AxiosによるWeb APIへのアクセス方法~その② 非同期プログラミング

【初心者向き】AxiosによるWeb APIへのアクセス方法~その① Axiosの使い方」の続きになります。

まずは前回のプログラム(医療機器の識別子を与えるとブランド名を返す)を複数呼び出せるように関数にします。

const axios = require('axios');

// 医療機器の識別子からブランド名を取得する
const getSingleDeviceRecord = async (di) => {
  const url = `https://accessgudid.nlm.nih.gov/api/v2/devices/lookup.json?di=${di}`;
  try {
    const res = await axios.get(url);
    return res.data.gudid.device.brandName;
  } catch (error) {
    return error.response.data.error;
  }
}

getSingleDeviceRecord('00302340989336') // 成功する
  .then((res) => {
    console.log(res);
  })
  .catch((res) => {
    console.log(res);
  })

getSingleDeviceRecord('xxxx') // エラーになる
.then((res) => {
  console.log(res);
})
.catch((res) => {
  console.log(res);
})

console.log('完了!');

実行すると次になります。

node test.js
完了!
No device found for DI xxxx
DUREX Pleasure Pack Condom
PS C:\Users\pitan\Documents\dev\test>

あれ?順序が逆ですよ??

これは次のような形で非同期で実行されているからです。

シーケンス図

上図の赤線の呼び出しを非同期呼び出しから同期呼び出しに変えるには、Promiseを使います。

関数の中身を以下で囲います。

return new Promise((resolve, reject) => {
    // ここに全部入れる。
});

そして関数が成功したら処理の成功を通知する関数(この場合はresolve)を呼び出します。

関数が失敗したら処理の成功を通知する関数(この場合はreject)を呼び出します。

それぞれの通知関数には、引数を与えることができます。

こんな感じです。

const axios = require('axios');

const getSingleDeviceRecord = (di) => {
  return new Promise(async (resolve, reject) => {
    const url = `https://accessgudid.nlm.nih.gov/api/v2/devices/lookup.json?di=${di}`;
    try {
      const res = await axios.get(url);
      resolve(res.data.gudid.device.brandName);
    } catch (error) {
      reject(error.response.data.error);
    }
  });
};

そして呼び出し側も順番に呼ばれるようにします。

そのためには上のコードで使っているようにawaitを使います。しかし、今 getSingleDeviceRecord を呼び出しているレベルではawaitが使えません。asyncを使った関数でしかawaitが呼べないからです。

仕方なく関数に包んでそれを呼ぶようにします。

const getDeviceRecords = async () => {  
  try {
    const res = await getSingleDeviceRecord('00302340989336'); // 成功する
    console.log(res);
  } catch (error) {
    console.log(error);
  }

  try {
    const res = await getSingleDeviceRecord('xxxx'); // エラーになる
    console.log(res);
  } catch (error) {
    console.log(error);
  }

  console.log('完了!');
};

getDeviceRecords();

実行結果は次です。

> node test2.js
DUREX Pleasure Pack Condom
No device found for DI xxxx
完了!

最後におさらいで10秒から0秒までカウントダウンするコードです。

10秒から6秒まではtenToSixという関数を使い、そこからさきはtenToSixも呼び出しているdisplayAfterOnSecondという関数を使ったものです。

const displayAfterOnSecond = num => {
  return new Promise(resolve => {
      setTimeout(() => {
          console.log(num);
          resolve();
      }, 1000);
  });
};

const tenToSix =  async () => {
  return new Promise(async(resolve) => {
    await displayAfterOnSecond(10);
    await displayAfterOnSecond(9);
    await displayAfterOnSecond(8);
    await displayAfterOnSecond(7);
    await displayAfterOnSecond(6);
    resolve();
   });
}

tenToSix()
  .then(() => displayAfterOnSecond(5))
  .then(() => displayAfterOnSecond(4))
  .then(() => displayAfterOnSecond(3))
  .then(() => displayAfterOnSecond(2))
  .then(() => displayAfterOnSecond(1))
  .then(() => displayAfterOnSecond(0));