[2024/08/29] JavaScript Promise および async / await の使い方(非同期処理を同期処理にする) (No.376)
[2024/08/28] JavaScript Promiseの使い方2(非同期処理に関連して) (No.375)
[2024/08/27] JavaScript Promiseの使い方(非同期処理に関連して) (No.374)
[2023/10/19] JavaScript jQueryのライブラリ「LightBox2」でJavascriptからの画像追加のテスト (No.329)
[2023/10/18] JavaScript jQueryのライブラリ「LightBox2」で「$.fn」のプロトタイプでの関数宣言ではまったこと (No.328)
-
×
[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 の操作方法
-
画像ファイルをHTMLに記述して拡大表示を行う場合に良く使う「LightBox2」で、 Javascriptのプログラムから画像追加のテストを行ってみました。
「LightBox2」と1個の画像のみの表示の場合は、以下の様な感じでHTMLを作れば画像の拡大表示ができます。■LightBox2の例
<!DOCTYPE html> <head> <link href="./js/lightbox2-2.11.4/css/lightbox.min.css" rel="stylesheet"> <script type="text/javascript" src="./js/jquery-3.6.0/jquery-3.6.0.min.js"></script> <script src="./js/lightbox2-2.11.4/js/lightbox-plus-jquery.min.js"></script> <script> // lightbox start $(function() { lightbox.option({ "positionFromTop": 150, }); }); </script> </head> <body> <h1>LightBox2-TEST</h1> <a href="./test-1.jpg" data-lightbox="album" > <img src="./test-1.jpg" id="" width="100" > </a> </body> </html>
上のHTMLでは特に難しくはありませんでした。 そこで、このHTMLにボタンと、10個の適当な画像ファイル(add-1.jpg ~add-10.jpg)を用意して、 そのボタンをクリックすることで、上記の「test-1.jpg」のファイルの後ろに表示する様にしてみます。
画像ファイルの指定を追加しやすくするために、<div id="imgdiv"></div> で囲っています。
この35行は、divタグ、aタグ、imgタグを1行で記述していますが、こうしないと余計なキャプションが付くための対策です。
■LightBox2の例・その2
<!DOCTYPE html> <head> <link href="./js/lightbox2-2.11.4/css/lightbox.min.css" rel="stylesheet"> <script type="text/javascript" src="./js/jquery-3.6.0/jquery-3.6.0.min.js"></script> <script src="./js/lightbox2-2.11.4/js/lightbox-plus-jquery.min.js"></script> <script> // lightbox start $(function() { lightbox.option({ "positionFromTop": 150, }); }); $(function() { $("#btn").on('click', function() { for (i = 1; i <= 10; i++) { var add = ""; add += '<a href="./add-'+i+'.jpg" data-lightbox="album" >'; add += '<img src="./add-'+i+'.jpg" width="100" >'; add += '</a>'; $("#imgdiv").append(add); } }); }); </script> </head> <body> <h1>LightBox2-TEST</h1> <button id="btn">add image</button> <div id="imgdiv"><a href="./test-1.jpg" data-lightbox="album"><img src="./test-1.jpg" width="100"></a></div> </body> </html>
「add image」をクリックする前の表示は以下の通りです。
「add image」を2回クリックした後の表示は以下の様になります。
画像のどれかをクリックすると「lightbox2」が機能し、画像の拡大が行われます。
JQuery でのセレクタに対する append メソッドで上手くいくのか懸念していましたが、今回のテストでは特に問題なく「lightbox2」は動作しました。
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
⇒JavaScript jQueryを使った checkbox の操作方法
-
画像ファイルをHTMLに記述して拡大表示を行う場合に良く使う「LightBox2」で、 プロトタイプでの関数宣言で最近はまったので忘備録的に記載します。
「LightBox2」自体の使い方は難しくなく、以下の様な感じでHTMLを作れば画像の拡大表示ができます。■LightBox2の例
<!DOCTYPE html> <head> <link href="./js/lightbox2-2.11.4/css/lightbox.min.css" rel="stylesheet"> <script type="text/javascript" src="./js/jquery-3.6.0/jquery-3.6.0.min.js"></script> <script type="text/javascript" src="./js/lightbox2-2.11.4/js/lightbox-plus-jquery.min.js"></script> <script> // lightbox start $(function() { lightbox.option({ "positionFromTop": 150, }); }); </script> </head> <body> <h4>LightBox2テスト</h4> <a href="./example1.jpg" data-lightbox="album" > <img src="./example1.jpg" id="" width="100" > </a> <a href="./example2.jpg" data-lightbox="album" > <img src="./example2.jpg" id="" width="100" > </a> <a href="./example3.png" data-lightbox="album" > <img src="./example3.png" id="" width="100" > </a> </body> </html>
上のHTMLでは何も問題は無いのですが、ここに以下の Javascript ファイルを読込んで、 そのファイル内の関数を呼出した時にエラーが発生しました。■Javascriptの例(test.js とする)
(function($) { $.fnc = {}; $.fnc.test = function () { // ただ単に"test"を表示させる alert("test"); }; })(jQuery);
それでは、先ほどのHTMLファイルに上記の「test.js」を追加してみます。■LightBox2の例・その2
<!DOCTYPE html> <head> <link href="./js/lightbox2-2.11.4/css/lightbox.min.css" rel="stylesheet"> <script type="text/javascript" src="./js/jquery-3.6.0/jquery-3.6.0.min.js"></script> <script type="text/javascript" src="./js/test.js"></script> <script type="text/javascript" src="./js/lightbox2-2.11.4/js/lightbox-plus-jquery.min.js"></script> <script> // lightbox start $(function() { lightbox.option({ "positionFromTop": 150, }); }); // test display $.fnc.test(); </script> </head> <body> <h4>LightBox2テスト</h4> <a href="./example1.jpg" data-lightbox="album" > <img src="./example1.jpg" id="" width="100" > </a> <a href="./example2.jpg" data-lightbox="album" > <img src="./example2.jpg" id="" width="100" > </a> <a href="./example3.png" data-lightbox="album" > <img src="./example3.png" id="" width="100" > </a> </body> </html>
このファイルをブラウザで開いても、「alert("test");」の実行が行われませんでした。
Chromeのデベロッパーツールでソースを開いて上記の16行目でブレイクさせると、「$.fnc」は「undefined」となっていました。 「undefined」なので当然「$.fnc.test();」は実行不可能でした。
「lightbox2」のJavascriptを読込むと、どうも「JQuery」のプロパティ(この表現が正しいかどうかも分かりませんが)がクリアされる様です。
それならばと「test.js」ファイルの読込を「lightbox2」の後に持ってきたら、「$.fnc.test();」が実行されアラートが表示されました。
少し、便宜的な方法かもしれませんが、何かの参考になればと思い記事を書きました。
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
⇒JavaScript jQueryを使った checkbox の操作方法