-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
Promise の使い方して以下の記事を書きましたが、今回は Promise を返す関数を同期的に処理するための async / await の使い方の記事を書いてみます。
⇒JavaScript Promiseの使い方(非同期処理に関連して)
⇒JavaScript Promiseの使い方2(非同期処理に関連して)
あらためて、Promise を使用した関数ですが、以下のものを使用します。■Promise を使用した関数例
// Promise を返す関数の宣言 function test_callback(timeoutval) { return new Promise(function(resolve) { setTimeout(function() { resolve(timeoutval); }, timeoutval); }); }
この関数は setTimeout を使ってタイムアウトした時に resolve で指定された関数を実行します。
それではこの関数を使用してみます。// テスト test_callback(1000).then((data) => { console.log('callback...OK:' + data); }); // test_callback()をCALLした直後にコンソール出力 console.log('test_callback:実行');
これを実行すると以下のものがコンソール出力されます。test_callback:実行 // 先にこのメッセージが表示 callback...OK:1000
2行目のメッセージは test_callback 内のタイムアウトが終わってからの表示となります。 これを逆順で表示させたい場合(ソース上の順番通り)には async / await を使うことになります。
■async / await を使って同期処理を行う
公式サイトには async / await の説明が以下の様にあります。
async function 宣言は非同期関数を宣言し、その中で await キーワードを使うことができます。 async および await キーワードを使用することで、プロミスベースの非同期の動作を、 プロミスチェーンを明示的に構成する必要なく、よりすっきりとした方法で書くことができます。
この説明によれば、非同期関数の宣言には「function」宣言の前に「async」を付けて関数宣言を行い、 Promise ベースの非同期の動作の前に「await」を付けることで、Promise ベースの非同期の動作を待つことができるようです。
上記の実行部分を1個の関数として以下の様に async / await を使って宣言します。async function sample_callback() { // テスト await test_callback(1000).then((data) => { console.log('callback...OK:' + data); }); // test_callback()をCALLした直後にコンソール出力 console.log('test_callback:実行'); }
この関数を実行すると、結果としてコンソールには以下の出力が行われます。
callback...OK:1000 test_callback:実行 // 後からこのメッセージが表示
await で宣言した部分の実行が終わってから、最後のコンソール出力が実行されました。
ここで await の処理を複数行う様にしてみます。async function sample_callback() { // テスト1 await test_callback(1000).then((data) => { console.log('callback...OK:' + data); }); // テスト2 await test_callback(2000).then((data) => { console.log('callback...OK:' + data); }); // テスト3 await test_callback(3000).then((data) => { console.log('callback...OK:' + data); }); // 最後のコンソール出力 console.log('最後のコンソール出力'); }
これを実行すると、以下のコンソール出力が実行されました。
callback...OK:1000 callback...OK:2000 callback...OK:3000 最後のコンソール出力
同期的に順次処理が行われていることが分かります。
今回の例では実際の処理として setTimeout を使ったタイマ待ちで、タイムアウト時の処理を行わせていますが、 実用的な処理においても、いろんな機能のメソッドの処理終了時にコールバック関数を呼ぶものがります。
この場合にも Promise で処理関数を宣言し、それを呼出す関数を async / await で行えば、 同期的に処理が行われるので、ソース的には上から下への流れに記述できると思います。
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
⇒JavaScript jQueryを使った checkbox の操作方法
PR -
Promise の使い方の1回目として以下の記事を書きましたが、エラー処理に付いては書いていませんでしたので、今回追加の記事を書いてみます。
⇒JavaScript Promiseの使い方(非同期処理に関連して)
あらためて、Promise の説明ですが、以下の様になります。■Promise の説明
// Promiseの生成 const Promise = new Promise((resolve, reject) => { // ここで何かの処理 // … if ( [成功]/[失敗]の判定 ) { resolve("OK"); // [成功] } else { reject("NG"); // [失敗] } }); // Promiseの実行 Promise.then((result) => { // 成功時は「resolve」から渡されるものが「result」に返される console.log(result); // "OK"が表示される }) .catch((error) => { // 失敗時は「reject」から渡されるものが「error」に返される console.log(error); // "NG"が表示される });
1回目の記事での例を以下に示します。// コールバック用の関数を再掲 function test_callback2(timeoutval) { return new Promise((resolve) { setTimeout(function() { resolve(timeoutval); // 成功時の関数をコール }, timeoutval); }); }
この関数は setTimeout を使ってタイムアウトした時に resolve で指定された関数を実行します。
setTimeout にはエラー等は発生することは無いのですが、仮に指定されたタイムアウト値が奇数の場合は失敗時とし、 偶数の場合には成功時として関数を書き変えてみます。// コールバック用の関数を再掲 function test_callback2(timeoutval) { return new Promise(function(resolve, reject) { setTimeout(function() { if ((timeoutval & 1) == 0) { resolve(timeoutval); // 成功時の関数をコール } else { reject(timeoutval); // 失敗時の関数をコール } }, timeoutval); }); }
■Promiseを使って失敗時と成功時の処理を追加したもの
test_callback2 は Promiseオブジェクトを返してきますので、成功時の処理を行う為に、then メソッドに関数を記述します。 成功時の戻り値が在る場合は引数を記述します。(以下の例では「data」にあたります)
また、失敗時の処理を行う為に、catch メソッドに関数を記述します。
以下に、実行例を示します。// 成功時のテスト test_callback2(1000).then((data) => { console.log('callback...OK:' + data); }).catch((data) => { // タイムアウト値が偶数なのでここは呼ばれない console.log('callback...NG:' + data); }); // 失敗時のテスト test_callback2(1001).then((data) => { // タイムアウト値が奇数なのでここは呼ばれない console.log('callback...OK:' + data); }).catch((data) => { console.log('callback...NG:' + data); });
結果としてコンソールには以下の出力が行われます。
callback...OK:1000 callback...NG:1001
■実際にエラーが起きる場合の例
上記の例では便宜的に失敗時の処理が発生する様にして例を示しましたが、 以下の例ではエラーが起きるであろう場合の例を記します。
以下の関数は XMLHttpRequest を使用してテキストファイルの取得をします。
XMLHttpRequest のロード後のイベントとして「onload」時の関数を、 レスポンスの HTTP ステータスに従って、成功時と失敗時の関数コールを変えています。
また、エラー時のイベントとして「onload」時の関数を、失敗時の関数コールを行う様にしています。
// XMLHttpRequest を使用してテキストファイルの取得 function getFile(url) { const promise = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = () => { if (xhr.status == 200) { // レスポンスの HTTP ステータスを解析 resolve(xhr); } else { reject(xhr); } }; xhr.onerror = () => { reject(xhr); }; xhr.send(null); }); return promise; }
これを使用する例を以下に記します。// 最初は存在するテキストファイル getFile('test.txt').then((xhr) => { console.log('test.txt:' + xhr.responseText); }).catch((xhr) => { console.log('test.txt...NG:' + xhr.statusText); }); // 存在しないテキストファイル getFile('aaa.txt').then((xhr) => { console.log('aaa.txt:' + xhr.responseText); }).catch((xhr) => { console.log('aaa.txt...NG:' + xhr.statusText); });
結果として、コンソールに以下のものが出力されます。 (test.txt の内容は”This is test.”の文字列が書かれています)test.txt:This is test. GET http://localhost/__IndexedDB/aaa.txt 404 (Not Found) // ここは2回目の getFile の xhr.send でエラーが発生する aaa.txt...NG:Not Found
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
⇒JavaScript jQueryを使った checkbox の操作方法
-
Promise は、JavaScript において、非同期処理のコールバック関数をより分かりやすく記述するための仕組みです。
非同期処理のコールバック関数の説明のため以下の様な関数があるとします。■コールバック関数の説明のための例
function test_callback(timeoutval, callback_func) { setTimeout(() => { callback_func(); }, timeoutval); }
この関数は時間を待った後で指定コールバック関数の実行するものです。
これを実際に使う場合は以下の様になります。// 非同期関数を用いて test_callback(1000, function() { console.log('callback...1000'); });
1000msec待って、「callback...1000」をデベロッパーツールのコンソールに出力されます。
■Promiseを使って上記の例を書き変えてみる
先ずはPromiseの説明ですが、Promiseオブジェクトの生成には2個関数の引数を持った関数を渡します。
以下の説明では2個の関数の引数名として「resolve」「reject」としていますが、 それぞれがPromise渡される関数内で処理成功時と失敗時の処理を行う関数を指定します。
引数関数の名前が「resolve」「reject」ですが、別にこの名前ではなくても他のものでも問題ありません。
また、「resolve」のみでもOKです。// Promiseの生成 const Promise = new Promise((resolve, reject) => { // ここで何かの処理 // … if ( [成功]/[失敗]の判定 ) { resolve("OK"); // [成功] } else { reject("NG"); // [失敗] } }); // Promiseの実行 Promise.then((result) => { // 成功時は「resolve」から渡されるものが「result」に返される console.log(result); // "OK"が表示される }) .catch((error) => { // 失敗時は「reject」から渡されるものが「error」に返される console.log(error); // "NG"が表示される });
上記のことを踏まえて、最初のコールバック関数の例を以下の様にします。
function test_callback2(timeoutval) { return new Promise((resolve) { setTimeout(function() { resolve(timeoutval); // 成功時の関数をコール }, timeoutval); }); }
これを実行するために以下の様にします。
test_callback2(1000).then((result) => { console.log('callback...' + result); });
結果コンソールには、1000msec待ってから「callback...1000」が出力されます。
結果的には Promise を使ってもさほど違いはありませんが、 最初の例の関数を、コールバック後の処理を繰り返したい場合に以下の様な記述になります。// コールバック関数のネストが深い!! test_callback(1000, function() { console.log('callback...1000'); test_callback(2000, function() { console.log('callback...2000'); test_callback(3000, function() { console.log('callback...3000'); }); }); });
1000msec待って「callback...1000」がコンソールに出力され、 その後、2000msec待って「callback...2000」が、さらに3000msec待って「callback...3000」が出力されます。
この感じではネストが深くなり、ソースが見にくいと思います。 これを解消する為に上記の Promise を使った関数を使用します。
■Promiseを使った処理の連結の例
// コールバック用の関数を再掲 function test_callback2(timeoutval) { return new Promise((resolve) { setTimeout(function() { resolve(timeoutval); // 成功時の関数をコール }, timeoutval); }); } // then で連結する test_callback2(1000).then((result) => { console.log('callback...' + result); return test_callback2(2000); }).then((result) => { console.log('callback...' + result); return test_callback2(3000); }).then((result) => { console.log('callback...' + result); });
最初の test_callback2 の then では成功時の処理を書きますが、コンソール出力後 再度、 test_callback2 を実行し、結果を return しています。 よって、この then の結果では return で Promise オブジェクトが返されてくるので さらに then で成功時の処理を書きます。
こうやって順次 then で結合することで、ネストが深くなることを防ぐことができます。
また、順次処理を行うことができます。
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
⇒JavaScript jQueryを使った checkbox の操作方法
-
表示される行番号にはエラーが無く、他の部分にエラーが在る場合が多いです。
例えば、if文などの{(中括弧)の閉じ忘れなどがあります。
また、今回くだらないミスを起こしたのですが、変数名の先頭の【$】ドルマークを忘れたことです。
長い変数名を使用していて、他の所からのコピペでささっとソースを直したら 【$】ドルマークをつけるのを忘れていて、解決するまで30分も掛かってしまいました。
{(中括弧)の閉じ忘れを中心に見直していたのですが、人間正しいと思いこむと 簡単な変数の【$】ドルマークを忘れるものです。笑ってやってください。
皆さんもくれぐれも変数の先頭の【$】ドルマークを忘れませんように。
尚、エラーの部分を特定する方法としては、 エラーが起きている部分を含む大まかなところで、 【/**/】コメントにしてエラーが出ない様にしてから、 順次内側にコメント部分を狭めていき見つける様にしています。
-
今日は、またまた簡単なエラーの件で恐縮ですが、 以下のソースで、「L_test()」の宣言でタイトルのエラーが発生しました。
「処理A」「処理B」共に長い処理だったので、なかなか見つからなかったのですが、 よくよく見ると、「switch」文の閉じる括弧「}」がありません。
こんな簡単なところにバグが潜んでいました。
論理的には問題無い様な感じだったので、括弧「{}」の対応をチェックするのを怠っていました。 完全にケアレスミスでした。
「unexpected 'private'」などと表示されたので、てっきり他の部分を疑っていましたが、 もっとソースをよく見るべきでした。
タイトルの様なエラーが出たら、一度処理の括りの括弧「{}」の対応を確認してみては 如何でしょうか。public function P_test($intMode){ $blnRet = true; // ----- // 処理A // ----- if($blnRet == true){ switch($intMode){ case 1: // 新規 case 2: // 修正 // ----- // 処理1 // ----- break; case 3: // 削除 // ----- // 処理2 // ----- break; default: } // ----- // 処理B // ----- } private function L_test(){ $blnRet = false; // 何か処理する }