こんにちは、まいまいです。
最近はindexedDBを使っているのですが、この前indexedDBを使っていると困ったことがありました。それは、DBへのアクセスが非同期で行われるためにコードが意図しない処理順になってしまう点です。
例えば、クリックされたらDBからデータを取得して表示したいと思い、
①クリックを感知
②DBにアクセス
③DBから値取得
④表示
という3流れでコードを書きましたが、実行されるのは
①クリックを感知
②DBにアクセス
③表示
④DBから値取得
という流れになるのです。(まったく意味ない。)
どうしたら解決できるのか考えた結果、コールバック処理が使えることが判明しました。
indexedDBで使えるコールバック関数の入れ方例
例えば「IDを入力してクリックすると、自分の名前が取得できる」というindexedDBのうログラムを考えるとします。その場合は、通常なら以下のように書くと思います。
let id = ユーザの入力; let name = “abcde”; name = getMyName(id); console.log(name); function getMyName(id){ let name = “”; // indexedDBでidからnameを取る処理。 return name; }
この関数を実行すると、残念ながら”abcde”が表示されてしまいます。indexedDBへのアクセスは非同期なのでgetMyName()の完了前に次のステップへ行ってしまい、変数nameが書き換えられることなくそのまま表示されてしまうのです。
この問題を解決する1つの方法がコールバックです。コールバックについての詳しい説明は省きますが、簡単に言うと引数に関数を入れる方法です。難しい話は無しにして、「あの引数に、値じゃなくて関数が入っているんだなー」と言う感覚でいいと思います。
そのコールバック関数を利用して非同期の問題を解決したものが以下になります。
let id = ユーザの入力; getMyName(id, consoleLog); function getMyName(id, callback){ //いろいろ処理 let openReq = objectStore.get(id); openReq.onsuccess = function(event){ let name = openReq.result.name; callback(name); } function consoleLog(text){ console.log(text); }
getMyNameという関数に2つの引数を渡しています。idとconsoleLogという関数です。consoleLogという関数に引数が必要ですが、この時点では引数に何も入れていなくて大丈夫です。(使うときには必ず引数を入れます。)
getMyNameという関数の定義を見ると、callbackという引数があります。ここに入るのがコールバック関数という関数です。(今回はconsoleLogという関数を入れている。)
そして、DBへのアクセスが成功してnameを無事に取り出せたときに、callback(name)を実行しています。こうすることで、nameを取り出してから表示するという順番を必ず守ることができました。
コールバック以外の解決方法
javascriptは非同期処理が多いようで、非同期を扱う方法はいくつか見つかりました。中でもコールバックはちょっと古いみたいで、より新しい方法としてはPromise、async / awaitという方法があるみたいです。
ただし、コールバックが最も基本的な対処法で、それ以外はコールバックを起点として発展してきたわけですから、まずはコールバックの使い方を押さえることが大切だと思います。自分はまだpromise, async / awaitは使えませんが、勉強を続けて使えるようになりたいです。
まとめ
indexedDBの非同期処理問題をコールバック関数で解決するサンプルをご紹介しました。コールバックが最も基本的な対処法ですが、複雑な非同期処理を扱うときは可読性が下がり、対処しきれないようです。その際にはpromiseやasync / awaitを使うといいと思います。自分も勉強していきます。
最後までお読みいただきありがとうございました。