次の方法で共有


Office アドインにおける非同期プログラミング

重要

この記事は、Office 2013 で導入された Office JavaScript API モデルである Common API に適用されます。 これらの API には、複数の種類の Office アプリケーション間で共通の UI、ダイアログ、クライアント設定などの機能が含まれます。 Outlook アドインは、共通 API、特に メールボックス オブジェクトを通じて公開される API のサブセットのみを使用します。

共通 API は、アプリケーション固有の API でサポートされていないシナリオにのみ使用してください。 アプリケーション固有の API ではなく共通 API を使用する場合については、「Office JavaScript API について理解する」を参照してください。

Office アドイン API で非同期プログラミングが使用される理由 JavaScript はシングル スレッド言語です。 スクリプトが Office クライアントの実行時間の長い同期プロセスを呼び出すと、そのプロセスが完了するまで後続のすべてのスクリプトがブロックされます。 非同期にすると、Office アドインの応答性が高く高速になります。

Common API 内のすべての非同期メソッドの名前は、 Document.getSelectedDataAsyncBinding.getDataAsyncItem.loadCustomPropertiesAsync メソッドなど、"Async" で終わるものです。 "Async" メソッドが呼び出されると、すぐに実行されます。 スクリプトの残りの部分は、クライアント側で操作が完了している間も続行されます。 "Async" メソッドに渡す省略可能なコールバック関数は、データまたは要求された操作の準備が整うとすぐに実行されます。 これは一般に迅速に発生しますが、若干の遅延が発生する可能性があります。

次の図は、ユーザーがドキュメントで選択したデータを読み取る "Async" メソッドのフローを示しています。 "Async" 呼び出しが行われると、JavaScript スレッドは追加のクライアント側処理を自由に実行できます (図には何も表示されません)。 "Async" メソッドが返されると、コールバックはスレッドで再開されます。 その後、アドインはデータにアクセスし、何らかの操作を行い、結果を表示できます。 パターンはプラットフォーム間で同じです。

ユーザー、アドイン ページ、アドインをホストする Web アプリ サーバーとの時間の経過に伴うコマンド実行の相互作用を示す図。

"Async" メソッドのコールバック関数を記述する

コールバック引数として "Async" メソッドに渡す コールバック 関数は、1 つのパラメーターを宣言する必要があります。 アドイン ランタイムでは、そのパラメーターを使用して、コールバック関数の AsyncResult オブジェクトへのアクセスを提供します。

コールバック関数には、匿名関数または名前付き関数を指定できます。 匿名関数は、コードを 1 回だけ使用する場合に便利です。名前がないため、コードの別の部分で参照することはできません。 名前付き関数は、コールバック関数を複数の "Async" メソッドに再利用する場合に便利です。

匿名コールバック関数を記述する

次の匿名コールバック関数は、クライアントから返されるデータの result という名前の 1 つのパラメーターを宣言します。 コールバックが返されるときに、 AsyncResult.value プロパティからそのデータを取得して書き込みます。

function (result) {
    write('Selected data: ' + result.value);
}

次の例は、 Document.getSelectedDataAsync(coercionType, callback) メソッドへの完全な "Async" メソッド呼び出しのコンテキストで、この匿名コールバック関数を示しています。

  • 最初の coercionType 引数 Office.CoercionType.Textは、選択したデータを文字列として返すように指定します。

  • 2 番目の コールバック 引数は、 メソッドにインラインで渡される匿名関数です。 関数は、実行時に result パラメーターを使用して、AsyncResult オブジェクトの value プロパティにアクセスします。 次に、ユーザーがドキュメント内で選択したデータを表示します。

Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, 
    function (result) {
        write('Selected data: ' + result.value);
    }
});

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message; 
}

コールバック関数の パラメーターを使用して、 AsyncResult オブジェクトの他のプロパティにアクセスすることもできます。 呼び出しの成功または失敗を判断する場合は AsyncResult.status プロパティを使用します。 呼び出しが失敗した場合は、 AsyncResult.error プロパティを使用して Error オブジェクトにアクセスして、何を行うかを判断してください。

getSelectedDataAsync メソッドの詳細については、「ドキュメントまたはスプレッドシートのアクティブな選択に対するデータの読み取りと書き込み」を参照してください。

名前付きコールバック関数を記述する

または、名前付き関数を記述し、その名前を "Async" メソッドの コールバック パラメーターに渡すことができます。 ここで、前の例は、コールバック パラメーターとして writeDataCallback という名前の関数を渡すように書き換えられます。

Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, 
    writeDataCallback);

// Callback to write the selected data to the add-in UI.
function writeDataCallback(result) {
    write('Selected data: ' + result.value);
}

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message;
}

AsyncResult.value プロパティに返される内容の違い

AsyncResult オブジェクトのasyncContextstatuserror プロパティは、すべての "Async" メソッドに渡されるコールバック関数に同じ種類の情報を返します。 ただし、 AsyncResult.value プロパティに返されるものは、"Async" メソッドの機能によって異なります。

たとえば、 addHandlerAsync メソッド ( BindingCustomXmlPartDocumentRoamingSettingsSettings オブジェクト) を使用して、イベント ハンドラー関数を追加します。 これらのコールバック関数の AsyncResult.value プロパティは、イベント ハンドラーを追加するときにデータまたはオブジェクトにアクセスしないため、常に 未定義を返します。

一方、 Document.getSelectedDataAsync メソッドを呼び出すと、ユーザーがドキュメントで選択したデータがコールバックの AsyncResult.value プロパティとして返されます。 または、 Bindings.getAllAsync メソッドを呼び出すと、ドキュメント内のすべての Binding オブジェクトの配列が返されます。

Async メソッドの AsyncResult.value プロパティに返される内容の説明については、そのメソッドのリファレンス トピックの「callback」セクションを参照してください。

非同期プログラミング パターン

Office JavaScript API の共通 API では、2 種類の非同期プログラミング パターンがサポートされています。

  • 入れ子になったコールバック
  • 約束

注:

現在のバージョンの Office JavaScript API では、promises パターンの組み込みサポートは、Excel スプレッドシートとWord ドキュメントのバインドのコードでのみ機能します。 ただし、コールバックを持つ他の関数は、独自のカスタム Promise返す関数内でラップできます。 詳細については、「 Promise を返す関数で共通 API をラップする」を参照してください。

入れ子のコールバック関数を使用する非同期プログラミング

多くの場合、タスクを完了するには、2 つ以上の非同期操作を実行する必要があります。 これを実現するために、1 つの "Async" 呼び出し内で別の呼び出しを入れ子にできます。

次のコード例では、2 つの非同期呼び出しを入れ子にしています。

  • 最初に、Bindings.getByIdAsync メソッドが呼び出され、"MyBinding" という名前のドキュメントのバインドにアクセスします。 そのコールバックの result パラメーターに返されるAsyncResult オブジェクトは、AsyncResult.value プロパティから指定されたバインド オブジェクトへのアクセスを提供します。
  • 次に、最初の result パラメーターからアクセスするバインド オブジェクトを使用して 、Binding.getDataAsync メソッドを呼び出します。
  • 最後に、Binding.getDataAsync メソッドに渡されるコールバックのresult2 パラメーターを使用して、バインド内のデータを表示します。
function readData() {
    Office.context.document.bindings.getByIdAsync("MyBinding", function (result) {
        result.value.getDataAsync({ coercionType: 'text' }, function (result2) {
            write(result2.value);
        });
    });
}

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message; 
}

この基本的な入れ子になったコールバック パターンは、共通 API 内のすべての非同期メソッドに使用できます。

promise パターンを使用してバインドのデータにアクセスする非同期プログラミング

コールバック関数を渡し、スクリプトが続行する前に関数が返されるのを待つ代わりに、promises プログラミング パターンは、その目的の結果を表す Promise オブジェクトを直ちに返します。 ただし、真の同期プログラミングとは異なり、 では、約束された結果の実現は、実際には Office アドインランタイム環境が要求を完了するまで延期されます。 要求が履行されない状況に対処するために onError ハンドラーが用意されています。

Common API には、既存のバインド オブジェクトを操作するときに promises パターンをサポートする Office.select 関数が用意されています。 Office.select関数に返される promise オブジェクトは、Binding オブジェクトから直接アクセスできる 4 つのメソッドのみをサポートします。

バインドを操作するための promises パターンは、この形式になります。

Office.select( selectorExpression,onError).BindingObjectAsyncMethod;

selectorExpression パラメーターは、"bindings#bindingId"フォームを受け取ります。bindingId は、ドキュメントまたはスプレッドシートで作成したバインドの名前 (id) です (Bindings コレクションの "addFrom" メソッドのいずれかを使用します:addFromNamedItemAsyncaddFromPromptAsync、またはaddFromSelectionAsync)。 bindings#citiesselectorExpression の例では、'cities' の ID を使用してバインドにアクセスすることを指定します。

onError パラメーターは、AsyncResult型の 1 つのパラメーターを受け取るエラー処理関数です。 これは、select関数が指定されたバインドへのアクセスに失敗した場合に、Error オブジェクトにアクセスするために使用されます。 次の例は、onErrorパラメーターに渡すことができる基本的なエラー処理関数を示しています。

function onError(result){
    const err = result.error;
    write(err.name + ": " + err.message);
}

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message; 
}

BindingObjectAsyncMethod プレースホルダーを、promise オブジェクトでサポートされている 4 つのBinding オブジェクト メソッド (getDataAsyncsetDataAsyncaddHandlerAsync、または removeHandlerAsync) への呼び出しに置き換えます。 これらのメソッドの呼び出しでは追加の promise がサポートされません。 その場合は、 入れ子になったコールバック関数パターンを使用する必要があります。

Binding オブジェクトの promise が満たされた後は、バインドであるかのように、チェーンされたメソッド呼び出しで再利用できます。 成功した場合、アドイン ランタイムは、約束の実行を非同期的に再試行しません。 Binding オブジェクトの promise を満たせない場合、アドイン ランタイムは、次にその非同期メソッドの 1 つが呼び出されたときに、バインド オブジェクトへのアクセスを再試行します。

次の例では、select 関数を使用して、Bindings コレクションから id "cities" を使用してバインドを取得し、addHandlerAsync メソッドを呼び出して、バインドの dataChanged イベントのイベント ハンドラーを追加します。

function addBindingDataChangedEventHandler() {
    Office.select("bindings#cities", function onError(){/* error handling code */}).addHandlerAsync(Office.EventType.BindingDataChanged,
    function (eventArgs) {
        doSomethingWithBinding(eventArgs.binding);
    });
}

重要

Office.select関数によって返されるBinding オブジェクト promise は、Binding オブジェクトの 4 つのメソッドにのみアクセスできます。 Binding オブジェクトの他のメンバーにアクセスする必要がある場合は、代わりに Document.bindings プロパティと Bindings.getByIdAsync メソッドまたは Bindings.getAllAsync メソッドを使用して、Binding オブジェクトを取得する必要があります。

省略可能なパラメーターを非同期メソッドに渡す

すべての "Async" メソッドの一般的な構文は、このパターンに従います。

asyncMethod(requiredParameters, [optionalParameters],callbackFunction);

すべての非同期メソッドは、省略可能なパラメーターをサポートします。 これらは JavaScript オブジェクトとして渡されます。 省略可能なパラメーターを含む オブジェクトは、キーと値のペアの 順序付けされていない コレクションです。 省略可能なパラメーターを含むオブジェクトをインラインで作成するか、 options オブジェクトを作成し、そのオブジェクトを options パラメーターとして渡します。

省略可能なパラメーターをインラインで渡す

省略可能なパラメーターをインラインで定義した Document.setSelectedDataAsync メソッドの 例を次に示します。 coercionTypeasyncContext という 2 つの省略可能なパラメーターは、匿名 JavaScript オブジェクトとして定義されています。

Office.context.document.setSelectedDataAsync(
    "<html><body>hello world</body></html>",
    {coercionType: "html", asyncContext: 42},
    function(asyncResult) {
        write(asyncResult.status + " " + asyncResult.asyncContext);
    }
)

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message; 
}

名前付きオブジェクトに省略可能なパラメーターを渡す

または、メソッド呼び出しとは別に省略可能なパラメーターを指定する名前付きオブジェクトを作成し、そのオブジェクトを options 引数として渡すこともできます。 次の例は、 options オブジェクトを作成する 1 つの方法を示しています。ここで、 parameter1value1など、実際のパラメーター名と値のプレースホルダーを指定します。

const options = {
    parameter1: value1,
    parameter2: value2,
    ...
    parameterN: valueN
};

ValueFormat パラメーターおよび FilterType パラメーターを指定する場合は次のようになります。

const options = {
    valueFormat: "unformatted",
    filterType: "all"
};

options オブジェクトを作成する別の方法を次に示します。

const options = {};
options[parameter1] = value1;
options[parameter2] = value2;
...
options[parameterN] = valueN;

ValueFormat パラメーターと FilterType パラメーターを指定するために使用した場合、次の例のようになります。

const options = {};
options["ValueFormat"] = "unformatted";
options["FilterType"] = "all";

次の例では、options オブジェクトで省略可能なパラメーターを指定して、Document.setSelectedDataAsync メソッドを呼び出す方法を示します。

const options = {
   coercionType: "html",
   asyncContext: 42
};

document.setSelectedDataAsync(
    "<html><body>hello world</body></html>",
    options,
    function(asyncResult) {
        write(asyncResult.status + " " + asyncResult.asyncContext);
    }
)

// Function that writes to a div with id='message' on the page.
function write(message){
    document.getElementById('message').innerText += message; 
}

どちらのオプションのパラメーター例でも、callback パラメーターが最後のパラメーターとして (インラインのオプションのパラメーターまたは options 引数オブジェクトに続けて) 指定されています。 または、インライン JavaScript オブジェクト内または options オブジェクト内でコールバック パラメーターを指定することもできます。 ただし、 コールバック パラメーターは、 options オブジェクト (インラインまたは外部で作成) 内の 1 つの場所、または最後のパラメーターとして渡すことができますが、両方を渡すわけではありません。

Promise返す関数で共通 API をラップする

Common API (および Outlook API) メソッドは Promise を返しません。 そのため、非同期操作が完了するまで await を使用して実行を一時停止することはできません。 await動作が必要な場合は、明示的に作成されたPromiseでメソッド呼び出しをラップします。

基本的なパターンは、Promise オブジェクトをすぐに返し、内部メソッドが完了したときに Promise オブジェクトを 解決 する非同期メソッドを作成するか、メソッドが失敗した場合にオブジェクトを 拒否 することです。 次に簡単な例を示します。

function getDocumentFilePath() {
    return new OfficeExtension.Promise(function (resolve, reject) {
        try {
            Office.context.document.getFilePropertiesAsync(function (asyncResult) {
                resolve(asyncResult.value.url);
            });
        }
        catch (error) {
            reject(WordMarkdownConversion.errorHandler(error));
        }
    })
}

この関数を待機する必要がある場合は、await キーワード (keyword)で呼び出すか、then関数に渡すことができます。

注:

この手法は、アプリケーション固有のオブジェクト モデルで run 関数の呼び出し内で Common API を呼び出す必要がある場合に特に便利です。 この方法で使用されているgetDocumentFilePath関数の例については、サンプル Word-Add-in-JavaScript-MDConversion のファイルHome.js を参照してください。

関連項目