
Javascriptを使っていると、callback地獄に悩まされます。
classをインスタンスする処理にcallbackをくっつけて、非同期で返ってくる値を受け取る場合、プログラムが煩雑になってしまうため、リファクタリングなどで読み直す時に、自分で書いたプログラムなのに、「ハァ?」ってなります。
async~awaitを使って、非同期を無理やり同期処理にしてもいいんですが、関数前にasyncを書き込む事が余儀なくされて、これも読み解きにくくなるケースもあります。
どれかの方式で一本にまとまった書き方ができるといいんですが、ケースバイケースで使うというのが、良さそうなので、今回関数にthenを使ったcallbackできる方法が書きたくて、そのやり方を調べてみました。
これまで書いてたcallback方式
new Callback({
  hoge : 'puyo',
  callback : res => {
    console.log(res)
  }
})
export class Callback{
  constructor(options){
    this.options = options || {}
    setTimeout(this.run.bind(this) , 1000)
  }
  
  // 時間のかかる処理実行
  run(){
    const data = (+new Date())
    this.options.data = data
    this.finish()
  }
  
  // 終了後の値の戻し
  finish(){
    if(!this.options.callback){return}
    this.options.callback(this.options)
  }
}
response > {hoge: 'puyo', data: 1675546948826, callback: ƒ}
thenでcallbackできる書き方
new Callback({
  hoge : 'hage'
}).then(e => {
  console.log('cb-4 : ' , e)
})
export class Callback{
  // 初期設定 : promiseの定義
  constructor(options){
    this.options = options
    return new Promise(this.promise.bind(this))
  }
  // promiseの基本開始処理
  promise(resolve){
    this.resolve = resolve
    this.run()
  }
  // 時間のかかる処理実行
  run(){
    setTimeout(this.proc.bind(this) , 3000)
  }
  // 時間のかかる処理終了
  proc(){
    const data = (+new Date())
    this.options.date = data
    this.finish()
  }
  // 終了後の値の戻し
  finish(){
    this.resolve(this.options)
  }
}
response > {hoge: 'hage', date: 1675546950831}
解説
callback記述の方が、プログラムが短いように見えるかもしれませんが、呼び出し部分の送り値がゴチャ!!っとしているのがこれまで気に入らなかったんですが、then方式で書くと、処理を追記できるような感じもあり、見た目スッキリです。
あと、戻り値に無駄なoptionがつくことがなく(これはデータの持たせ方によるので、これに限りませんが)、キレイな値が受け取れます。
ポイントは、Promise関数を実行する受け取り確認のresolveを、インスタンスの中で共有することで、class内のどこでも受け取り可能になり、class全体のどこでもthen対応ができるようになるのが便利そうですね。
class内のconstructor内でPromiseをreturnしているので、thenが起動処理で使えるようになっているんですが、個人的には、constructor内のreturnって、インスタンスで有効なのかどうか実は不安な書き方なんですよね。
[おまけ] async~awaitの書き方
const res = await new Callback({hoge : 'test'})
console.log(res)
Promise処理をした、callback.jsをそのまま使って、awaitをつけるだけで、非同期を同期処理として受け取ることが可能になります。
値を受け取るだけなら、この方式の方が記述が楽ですね。
callbackして処理継続するか、値を受け取ってその場で処理をするかの違いで使い分けられそうです。
注意点
awaitをfunction内に書く場合は、functionの手前に"async"をつけるのを忘れないようにしましょう。(エラーになります)
async function run(){await new Callback(...)}
こんな感じで書いてください。
あとがき
javascriptでやたらとcallbackが増えて困っていたので、これでまた一段回整ったプログラミングが書けるようになった気がします。
これまでのプログラムを全て書き換えてでも対応したいですね。
あ、とりあえず、can i useしておきます。

もちろん、IEは使えません・・・でも、もういいですよね?
 
0 件のコメント:
コメントを投稿