非同期JavaScriptコードを定義する
JavaScriptは、ほとんどの場合シングルスレッドです。ブラウザでJavaScriptコードを実行しているスレッドは、レンダリング処理とすべてのユーザーインタラクションをブロックします。
このブロック動作を回避するために、サーバーへのリクエスト、およびモバイルアプリのプラグインを利用した写真の取り込みなど、時間がかかることが想定されるJavaScriptコールは、非同期APIを備えています。これにより、APIを呼び出すコードはコールの結果が利用可能になり次第取得(および対応)できるようになります。
Promiseを使用すると、非同期操作を実行、構成、管理できます。これにより、非同期メソッドが同期メソッドのように値を返すことが可能になります。ただし非同期メソッドは、未来のある時点までは最終値ではなくPromiseを返します(最終値を返さないこともあります)。
Promiseの使用の詳細については、Promiseに関するMozilla Developer Networkのドキュメントをご覧ください。
非同期クライアントアクションを定義する
JavaScript要素では、次の2つの事前定義された関数が使用できます: "$resolve()"および"$reject()"。これらの関数は、Promiseと一緒に使用される通常のresolve()およびreject()機能に酷似していますが、$resolve()は引数を受け取りません。出力値は事前定義された$parametersオブジェクトを使用して設定する必要があります。
あるJavaScript要素で、事前定義された$resolve()または$reject()関数のどちらかが使用されている場合、その要素が属するクライアントアクションは非同期とみなされます。さらに、あるクライアントアクションにサーバーアクションの実行やAggregateの更新などのサーバー呼び出しが含まれる場合も、クライアントアクションは非同期とみなされます。
これら2つの事前定義された関数のうち1つを含む要素について生成されたコードは、Promiseの作成に囲まれています。そのため、JavaScript要素のコードに手動でPromiseを作成する必要はありません。
非同期クライアントアクションの終了を呼び出し側に知らせる方法
呼び出された非同期クライアントの実行完了を知らせるには、事前定義された$resolve()関数を使用します。
たとえば、GlobalAsyncActionクライアントアクションがあり、実行完了を呼び出し側に知らせたい場合は、以下のコードをJavaScript要素のアクションフローのsuccessパスに追加します。
// Return success in GlobalAsyncAction client action $parameters.Success = true; $parameters.Out1 = 5.0; $resolve();
事前定義された$resolve()関数は、一切の引数を受け取りません。クライアントアクションの出力値を定義するには、上記のとおり事前定義された$parametersオブジェクトを使用します。
同じコード構成を使用して、非同期クライアントアクションの実行中にエラーが発生したことを知らせることができます。上記の例に従い、GlobalAsyncActionクライアントアクションで呼び出し側にエラーを知らせるには、JavaScript要素の下部に表示されているコードをアクションフローのfailureパスに追加します。
// 1st approach: return failure in GlobalAsyncAction client action using an output parameter $parameters.Success = false; $parameters.ErrorMessage = "A custom error message"; $resolve();
また、以下の例のようにErrorオブジェクトで$reject()を呼び出すこともできます。この場合、Promiseのcatch(onRejected)メソッド(次のセクションを参照)によってエラー処理コードが定義されていればそれが実行されます。
// 2nd approach: return failure in GlobalAsyncAction client action using $reject(...) $reject(new Error("A custom error message"));
Errorオブジェクトを引数として含めない場合、$reject()メソッドが呼び出されたJavaScript要素名を説明するメッセージとともに、デフォルトのErrorオブジェクトが作成されます。
OutSystemsでは、事前定義された関数である「$reject()」によってのみ例外がトリガーされ、最初の利用可能な例外ハンドラによって処理されます。
モジュール内でカスタム例外ハンドラを定義していない場合、デフォルトのグローバル例外ハンドラによって例外が処理されます。詳細については、例外処理の仕組みをご覧ください。
非同期クライアントアクションを呼び出す
非同期クライアントアクションが呼び出されると、その戻り値は同期の場合のようにJavaScriptオブジェクトではなく、Promiseとなります。出力パラメータ値は返されたPromiseを通じて、未来に利用可能になります(最終的に利用可能にならない場合もあります)。
これらの値を処理するコードは、返されたPromiseでサポートされているthen(onFullfilled)メソッド呼び出しに含める必要があります。onFullfilled引数は、以下の例のように指定する必要があるコールバック関数です。
// call the GlobalAsyncAction asynchronous client action $actions.GlobalAsyncAction().then(function(result) { $parameters.Success = result.Success; if (result.Success) { $parameters.MyOutput = result.Out1; console.log($parameters.MyOutput); } // if the current client action is being invoked asynchronously, this call will resolve its promise $resolve(); });
resultパラメータは、呼び出された非同期クライアントアクションの出力パラメータを含むオブジェクトです(出力パラメータが存在する場合)。
未処理のエラー、または非同期クライアントアクションで発生した$reject()の呼び出しに対応することもできます。これを行うには、以下の手順のいずれかを実行します。
- 2番目の引数をthen()メソッドに追加します。このフルシグネチャはthen(onFullfilled, onRejected)であり、onRejectedは非同期アクションで$reject()が呼び出された場合に呼び出されるコールバック関数です。
- Promiseでもあるthen()メソッドの戻り値を、エラーケースに対応するcatch(onRejected)メソッドと連鎖させます。この連鎖処理は「コンポジション」と呼ばれます。
catch(onRejected)を使用した例:
// Using this approach, success/failure is signaled through the "Success" output parameter $actions.GlobalAsyncAction().then(function(result) { $parameters.Success = result.Success; if (result.Success) { $parameters.MyOutput = result.Out1; console.log($parameters.MyOutput); } $resolve(); }).catch(function(err) { // err will contain an Error object, either due to an unhandled error or to $reject(...) having been called $parameters.Success = false; $parameters.ErrorMessage = err.message; $resolve(); });
上記の例では、catch()コールバック関数はSuccessを「false」に設定し、ErrorMessage出力パラメータにエラーメッセージを保存して$resolve()を呼び出すことで、エラー関連データをJavaScript要素の出力パラメータとしてカプセル化しています。この場合、then()およびcatch()コールバック関数はいずれも$resolve()コールで終わります。
非同期コールが成功した場合$resolve()を使用して、catch()コールバック関数の終わりに$resolve()ではなく$reject(...)を使用する方法もあります。
// Example using the $resolve()/$reject(...) approach $actions.GlobalAsyncAction().then(function(result) { $parameters.MyOutput = result.Out1; console.log($parameters.MyOutput); $resolve(); }).catch(function(err) { // err will contain an Error object, either due to an unhandled error in GlobalAsyncAction // or to $reject(...) having been called in the same action console.log("An error occurred in GlobalAsyncAction: " + err.message); $reject(err); });
catch()で対応されない$reject(...)コールまたはエラーは、デフォルトではエラーフィードバックメッセージを作成します。これはアプリケーション画面の最上部に表示されます。
上記2つのアプローチのうちいずれかを使用してJavaScriptで非同期クライアントアクションを呼び出す場合、常にエラー処理コードを含める必要があります。"then(onFullfilled, onRejected)" or "catch(onRejected)".このエラー処理コードは、呼び出された非同期アクションが$reject()メソッドを起動する際、または呼び出された非同期クライアントアクションで未処理のJavaScriptエラーが発生している際に使用されます。
JavaScriptでの同期クライアントアクションを呼び出す場合、非同期クライアントアクションの呼び出しとは異なるコーディングを行う必要があります。
-
同期クライアントアクションを呼び出す場合、戻り値は出力パラメータを含むシンプルなJavaScriptオブジェクトです。
-
非同期クライアントアクションを呼び出す場合、Promiseが戻されます。つまり、戻り値は呼び出し側のコンテキストに返された後すぐには利用可能にはなりません。このことを念頭に置いてJavaScriptコードを作成しないと、後に続くロジックが無効なデータに基づいて作動する可能性があります。