LoginSignup
1
1

expressで非同期なviewを扱う

Last updated at Posted at 2024-04-03

小ネタです。

古典的なMVC2の実装をNode(Express)でするとなった時、Viewでモデルの振る舞いを呼び出すときにその処理が非同期だった場合詰みがちである。

故に振る舞いをもったモデルの代わりに解決済みのプレーンなデータをViewに渡す実装や設計が多くみられるのだが、そうなるとやはりプレゼンター的な層ができあがってしまいView内とそこで似たようなループ処理などが発生しがちである。

こういった問題を避けるためにそもそもMVC2じゃないアーキテクチャを使ったりいろんな解決方法があるわけだが、そもそもViewが非同期に対応してればいいんじゃないという漠然とした思いがあった。

ってわけで色々調べてるとどうやら古き懐かしのejsには非同期を扱うためのオプションがあるらしい。

async: When true, EJS will use an async function for rendering. (Depends on async/await support in the JS runtime.

ただexpress-generatorで単純にejsを指定するだけで使えるってわけではなかったのでExpressのソースを読みながらasyncオプションを設定できるようちょっと調整した

app.js
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
/* ここのところ追加 */
app.engine('ejs', async function (path, option, callback) {
  try {
    let html = await ejs.renderFile(path, option, {async: true});
    return callback(null, html);
  } catch (err) {
    return callback(err);
  }
});

で、試しにとテンプレ描画するところで非同期関数を渡してみる

1秒後にomataseって文字列返すように実装

routes/index.js
router.get('/', function(req, res, next) {
  res.render('index', { asyncMethod: function () {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve('omatase!'), 1000);
    });
  }});
});

で、テンプレ内でawaitしてみる。

うーん、viewでawait見るとキモくて草

views/index.js
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>テストアプリ</title>
    <link rel='stylesheet' href='/stylesheets/style.css'>
  </head>
  <body>
    <p><%= await asyncMethod(); %></p>
    <%- await include('./_partial', {asyncMethod}) %>
  </body>
</html>

パーシャルもpromise返すようになるのでawaitしてあげる

partialの中でも当然awaitつかえるんだよねって確認コード

views/_partial.ejs
<p>hello</p>
<p><%= await asyncMethod() %></p>

試してみたらちゃんと動いてて草

スクリーンショット 2024-04-03 15.52.03.png

レスポンスもちょうどawait2回分で2秒になっていた。

ほーん、やるじゃん。 railsつかお。

1
1
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
1