LoginSignup
1
0

More than 3 years have passed since last update.

Promiseを受け取るelement.innerHTMLで非同期処理を隠蔽

Posted at

非同期処理を同期処理のように書きたい

というニーズがあるらしい。確かに、promise.then()awaitを何回も書くのが煩わしいという気持ちは分かる。
そこで、promise.then()awaitを使わずに、普通の代入文のみで非同期処理を書いてみようというのがこの記事の趣旨。

方法1:代入式の右辺が必ず値を返すようにする

例えば「promiseが解決されていれば値を返し、解決されていなければpromiseをthrowする」という方法がある。Reactで使われているらしい。よく知らない。

方法2:代入式の左辺がPromiseを受け取れるようにする

こっちが本題。
fetchやら何やらで値を取ってきて処理するとして、その値は最終的にHTMLの書き換えに使われる(ことが多い)はず。
というわけで、Element.prototype.innerHTMLを書き換えてpromiseを受け取れるようにする

実装

Element.prototype.innerHTMLの書き換えについてはこちらのサイトを参考にさせて頂いた。
Promiseが解決されるまでは「loading...」と表示する。

{
const desc = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML')
Object.defineProperty(Element.prototype, "innerHTML", {
  get: function(){
    return desc.get.call(this)
  },
  set: function(x){
    if (x instanceof Promise || (x && typeof x.then === 'function')) {
      //Promiseだった場合、解決されるまで'loading...'を表示する
      desc.set.call(this, 'loading...')
      x.then(val=>desc.set.call(this, val))
    } else {
      //Promise以外の場合、そのまま表示する
      desc.set.call(this, x)
    }
  }
})
}

使用例

//1秒後に解決されるPromiseをinnerHTMLに代入
document.body.innerHTML = new Promise(resolve=>{
  setTimeout(_=>resolve('resolveされました'), 1000)
})

これを実行すると、まず「loading...」が表示され、1秒後に「resolveされました」が表示される。

なお、実際に使うときは、
- promise内でエラーが出た場合(promise.catch())
- element.innerTextやelement.insertAdjacentHTML
への対応が必要だと思われる。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0