メインコンテンツまでスキップ

非同期処理の実装

今回は非同期処理の概要と、Office スクリプトにおける非同期処理の実装方法をサンプルコードと併せて解説します。

非同期処理について

非同期処理とは言葉の通り、同期的に実行されない処理のことを表します。

実装方法の説明の前に、以下のコードをご覧ください。

fetch関数の型定義
function fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;

これは外部サービスからデータを取得するfetch関数の型定義情報です。

関数の返り値がPromiseでラップされているのが分かると思います。

非同期処理の結果は全てこのPromiseでラップされ、「結果が返ってきているか分からない状態」を表します。

fetch関数を使ったサンプル
async function fetchGoogle() {
const response = await fetch('https://www.google.com');

console.log('Googleからデータを取得しました');
}

function main(workbook: ExcelScript.Workbook) {
fetchGoogle();

console.log('Googleからデータを取得した後の処理です');
}

上記のサンプルは、非同期関数fetchGoogleを定義し、main関数から呼び出しています。

fetchGoogleの実装は現段階では「非同期に結果が返ってくる(Promiseを返す)関数」とだけ理解していただければ問題ありません。注目していただきたいのは、main関数の挙動です。

期待する動作はfetchGoogleが完了した後に、main関数内の後続する処理が実行されることだと思いますが、実際の結果は以下のようになります。

実行結果
Googleからデータを取得した後の処理です
Googleからデータを取得しました

main関数内の後続する処理が先に動作してしまっているのが分かります。

このように、非同期処理を待機する命令が指定されていない場合、Promiseでラップされた非同期処理の結果は、完了を待たずして後続の処理が実行されます。

非同期関数を待機するパターン
async function fetchGoogle() {
const response = await fetch('https://www.google.com');

console.log('Googleからデータを取得しました');
}
async function main(workbook: ExcelScript.Workbook) {
await fetchGoogle();

console.log('Googleからデータを取得した後の処理です');
}

main関数のfunctionの前にasyncを、fetchGoogle();の手前にawaitを追加しました。

これであれば、期待した結果を得ることができます。

実行結果
Googleからデータを取得しました
Googleからデータを取得した後の処理です

async/await を使った非同期処理

Office スクリプトで最も推奨される非同期処理の記述方法はasync/awaitを使用する方法です。

実行する関数のfunctionの前にasyncを付け、非同期で結果を返す関数の前にawaitを付けることで、非同期関数の結果を取得するまで処理を待機します。

async/awaitを使ったサンプル
async function main(workbook: ExcelScript.Workbook) {
/** Googleのウェブサイトからのレスポンス */
const google = await fetch('https://www.google.com');

console.log('Googleからデータを取得しました');

/** Yahooのウェブサイトからのレスポンス */
const yahoo = await fetch('https://www.yahoo.co.jp');

console.log('Yahooからデータを取得しました');
}

Promise を使った非同期処理

前述した通り、非同期関数の結果は全てPromiseオブジェクトでラップされているため、Promiseオブジェクトのメソッドが利用できます。

この場合は、functionの手前にasyncを付ける必要はありません。

async/awaitを使ったサンプル
function main(workbook: ExcelScript.Workbook) {
fetch('https://www.google.com')
.then((google) => {
console.log('Googleからデータを取得しました');

return fetch('https://www.yahoo.co.jp');
})
.then((yahoo) => {
console.log('Yahooからデータを取得しました');
});
}

async/awaitパターンと比較していただくと、このPromise.thenによるメソッドチェーンを使った方法は通常の同期処理と記述方法が大きく異なるため、可読性が低下しかねません。

避けられない場合を除き、async/awaitを使用することをおすすめします。