Web系や機械学習を勉強中。医療におけるIT活用に興味があります。Lambdaは関数が非同期に応答を返すための方法を2つ用意しています。1つは引数で渡されるcallback()関数を呼び出す方法で、もう1つはasync/awaitを用いる方法です。responseが発生してしまいました。これに関連して、今回は複数の非同期応答の優先順位について調べたので書き残しておきたいと思います。Lambdaのレスポンス冒頭で述べたとおり、Lambdaで非同期に応答を返すための方法は2つあります。...)}どちらも公式ドキュメントで紹介されています。個人的には後者がスマートに見えるので好きですが、callbackを用いたほうが良い場合もあります。callbackを引数に取るライブラリではcallbackが便利ライブラリによってはasync/awaitに対応しておらず、第2引数にcallbackを取るような関数があります。この場合でも自分でPromiseをreturnして、ライブラリに渡すcallback関数の中でresolve()を呼べばlambdaHandlerをasyncにできますが、自分でresolveを作るくらいなら、素直にhandlerでcallbackを受け取ってそれを呼んだほうが自然だと思います。(async関数内)上の2つの方法、asyncとcallbackを混在させるとどうなるでしょうか。例として、いくつかの簡単なコードを見てみましょう。async関数内において、setTimeout()の待機後にcallback()を呼ぶようにセットし、セット直後にreturnをした場合です。msの待機が生じるのに対し、returnに達するまでには待機が生じないので、returnのほうが先に到達し、その時点で実行は中断され、応答が返されます。(not-async関数内)先程のコードとの違いは、handler関数がasyncでないことだけです。ms)今度はcallbackの勝ちです。応答時間の延長からも、callback()が呼ばれるまで待ってくれていることが分かります。実際のレスポンスは先に到達するreturnによるものではなくcallback()によるものだと分かりました。先の例ではcallback()まで到達しなかったため、returnによる応答が優先されましたが、returnとcallback()の両方に到達した場合、常にcallback()による応答が優先されるのでしょうか?別のケースを見てみましょう。(async)今度は、setTimeout()を設定しない場合を見ていきます。async関数の場合です。callback()が先に呼ばれ、returnのほうが後に到達するはずですが、応答の中身はcallback()によるものであることが分かります。async関数でもreturn前(=Promiseのresolve前)にcallback()が呼ばれた場合は、応答の中身はcallbackが優先されるのですね。(non-async)上を踏まえれば自然なことですが、non-async関数でもcallbackが優先されます。以上より、callback()とreturnの両者が呼ばれた場合、handlerがasync関数であるかに関わらず、callbackが優先されることが分かりました。callback()が2回以上呼ばれる場合はどうでしょうか。msのsetTimeoutを待機してくれていることは分かります。これに関しては、公式のドキュメントを読むことで理解できます。callbackWaitsForEmptyEventLoopが重要です。loopが空になるまで待機されるのです。その中身は最初に呼ばれたcallback()によるものとなります。優先順位のまとめhandlerにcallback()とreturnが共に存在するとき、一番最初に呼ばれたcallback()が応答の中身となる。async関数の場合はPromiseがresolveされた時点(=returnに達した時点)で実行は終了し応答する。non-async関数の場合、イベントループが空になるまで待つので、returnに達した後でも終了は待機され、callback()が呼ばれればそちらが優先される。Gatewayのあるエンドポイントと紐付けたとしましょう。responseが発生します。このエラーはLambda関数からの応答がmalformed、つまり、不正なフォーマットであったことを意味します。その多くは、bodyをJSON.stringifyし忘れていることにより生じますが、今回の場合は違います。実際にLambda関数を実行してみると、この関数はnullを返却します。loopが空になるまで待たず、Promiseのresolveをもって実行を終了してしまうということです。ms後ですが、その前に関数の最終行に達してしまうため、Promiseがresolveされてしまいます。今回の例では明示的に値を返してませんから、すなわちreturn;と同じ扱いになります。したがって、nullを返すわけですね。async/awaitによる応答を行わない、すなわち関数がnon-asyncであったのならば、callbackWaitsForEmptyEventLoopが働き、setTimeout()内のcallback()まで待機されます。普通はcallbackを用いるときはnon-async関数内でしょうから、このような問題に気づきにくいのでしょう。これを避けるには、callback()で応答を返すのかasync/awaitで応答を返すのかを揃えた方が良いように思われます。私の場合は、結局古いライブラリ(callbackが必要な方)の関数をpromisifyしてasync/awaitによる方法で揃えました。記事一覧へコメントフォームは設置していませんので、ご意見・ご感想などはTwitter(@cosnomi)などへお願いします。