@ledsun blog

Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。

JS::Object.await

fetchは非同期だった - @ledsun blog でfetchの完了をRuby側で待てなくて、require_relativeの順番の制御が上手く行きませんでした。 ruby.wasmでJS::Object.awaitという関数を見つけました。 名前からするとPromiseを待てそうな関数です。 これを使えばfetchでrequire_relativeが実現できるのでしょうか?

次のようなrequire_relativeの代替え関数を用意します。

function rb_require_relative(relative_feature): Promise<boolean> {
  const filename = relative_feature.endsWith(".rb")
    ? relative_feature
    : `${relative_feature}.rb`;
  const url = new URL(filename, vm.currentURL);

  // Prevents multiple loading.
  if (loadedPathes.has(url.pathname)) {
    return Promise.resolve(false);
  }

  return new Promise((resolve, reject) => {
    fetch(url).then((response) => {
      if (response.ok) {
        response.text().then((text) => {
          new RubyScriptWithSourceURL(vm, url, text).eval();
          resolve(true);
        });
      }
      resolve(false);
    });
  });
};

これを次のようなRubyの関数で待てれば良さそうです。

require "js"
module Kernel
  def patched_require_relative(relative_feature)
    JS.global.rb_require_relative(relative_feature).await
  end
end

試して見たところ、そうはならないんですよ。

This method looks like a synchronous method, but it actually runs asynchronously using fibers.

コメントにこう書いてあるとおり、実際には非同期に実行されるので、require_relativeの実行順序は維持できないのでした。