MathJaxをデバッグしてJavaScriptの理解を深める ページ3

提供:yonewiki
2022年12月4日 (日) 23:27時点におけるYo-net (トーク | 投稿記録)による版 (→‎t.loadAll)

VScodeで簡易WebServerの元でデバッグに戻る。

概要

 MathJaxをデバッグしてJavaScriptの理解を深める ページ2の続きです。

[1] [2] [3] [4]


__webpack_modules__[265].call(r.exports, r, r.exports, __webpack_require__)

265:
function(t, e, r) {
  var n, o = this && this.__extends || (n = function(t, e) {
    return n = Object.setPrototypeOf || {
      __proto__: []
    }
    instanceof Array && function(t, e) {
      t.__proto__ = e
    } || function(t, e) {
      for(var r in e) Object.prototype.hasOwnProperty.call(e, r) && (t[r] = e[r])
    }, n(t, e)
  }, 
  function(t, e) {
    if("function" != typeof e && null !== e) 
      throw new TypeError("Class extends value " + String(e) + " is not a constructor or null");

    function r() {
      this.constructor = t
    }
    n(t, e), t.prototype = null === e ? Object.create(e) : (r.prototype = e.prototype, new r)
  }),
  i = this && this.__values || function(t) {
    var e = "function" == typeof Symbol && Symbol.iterator,
      r = e && t[e],
      n = 0;
    if(r) return r.call(t);
    if(t && "number" == typeof t.length) return {
      next: function() {
        return t && n >= t.length && (t = void 0), {
          value: t && t[n++],
          done: !t
        }
      }
    };
    throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
  },
  s = this && this.__read || function(t, e) {
    var r = "function" == typeof Symbol && t[Symbol.iterator];
    if(!r) return t;
    var n, o, i = r.call(t),
      s = [];
    try {
      for(;
           (void 0 === e || e-- > 0) && !(n = i.next()).done;
         ) 
        s.push(n.value)
    } 
    catch(t) { o = { error: t } } 
    finally { 
      try { n && !n.done && (r = i.return) && r.call(i) } 
      finally { if(o) throw o.error }
    }
    return s
  },
  a = this && this.__spreadArray || function(t, e, r) {
    if(r || 2 === arguments.length)
      for(var n, o = 0, i = e.length; o < i; o++) 
        !n && o in e || (n || (n = Array.prototype.slice.call(e, 0, o)), n[o] = e[o]);
    return t.concat(n || Array.prototype.slice.call(e))
  };
  Object.defineProperty(e, "__esModule", {
    value: !0
  }), 
  e.Package = e.PackageError = void 0;
  var l = r(235),
    c = function(t) {
      function e(e, r) {
        var n = t.call(this, e) || this;
        return n.package = r, n
      }
      return o(e, t), e
    }(Error);
  e.PackageError = c;
  var u = function() {
    function t(e, r) {
      void 0 === r && (r = !1), 
      this.isLoaded = !1, 
      this.isLoading = !1, 
      this.hasFailed = !1, 
      this.dependents = [], 
      this.dependencies = [], 
      this.dependencyCount = 0, 
      this.provided = [], 
      this.name = e, 
      this.noLoad = r, 
      t.packages.set(e, this), 
      this.promise = this.makePromise(this.makeDependencies())
    }
    return Object.defineProperty(t.prototype, "canLoad", {
      get: function() {
        return 0 === this.dependencyCount && !this.noLoad && !this.isLoading && !this.hasFailed
      },
      enumerable: !1,
      configurable: !0
    }), 
    t.resolvePath = function(t, e) {
      void 0 === e && (e = !0);
      var r = {
        name: t,
        original: t,
        addExtension: e
      };
      return l.Loader.pathFilters.execute(r), r.name
    }, 
    t.loadAll = function() {
      var t, e;
      try {
        for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) {
          var o = n.value;
          o.canLoad && o.load()
        }
      } 
      catch(e) { t = { error: e } } 
      finally {
        try { n && !n.done && (e = r.return) && e.call(r) } 
        finally { if(t) throw t.error }
      }
    }, 
    t.prototype.makeDependencies = function() {
      var e, r, n = [],
        o = t.packages,
        c = this.noLoad,
        u = this.name,
        p = [];
      l.CONFIG.dependencies.hasOwnProperty(u) ? 
        p.push.apply(p, a([], s(l.CONFIG.dependencies[u]), !1)) 
      : 
        "core" !== u && p.push("core");
      try {
        for(var h = i(p), f = h.next(); !f.done; f = h.next()) {
          var d = f.value,
            m = o.get(d) || new t(d, c);
          this.dependencies.indexOf(m) < 0 && 
          (
            m.addDependent(this, c), 
            this.dependencies.push(m), 
            m.isLoaded || (this.dependencyCount++, n.push(m.promise))
          )
        }
      } 
      catch(t) { e = { error: t } } 
      finally { 
        try { f && !f.done && (r = h.return) && r.call(h) } 
        finally { if(e) throw e.error }
      }
      return n
    }, 
    t.prototype.makePromise = function(t) {
      var e = this,
        r = new Promise((function(t, r) {
          e.resolve = t, e.reject = r
        })),
        n = l.CONFIG[this.name] || {};
      return n.ready && (r = r.then((function(t) {
        return n.ready(e.name)
      }))), t.length && (t.push(r), r = Promise.all(t).then((function(t) {
        return t.join(", ")
      }))), n.failed && r.catch((function(t) {
        return n.failed(new c(t, e.name))
      })), r
    }, 
    t.prototype.load = function() {
      if(!this.isLoaded && !this.isLoading && !this.noLoad) {
        this.isLoading = !0;
        var e = t.resolvePath(this.name);
        l.CONFIG.require ? this.loadCustom(e) : this.loadScript(e)
      }
    }, 
    t.prototype.loadCustom = function(t) {
      var e = this;
      try {
        var r = l.CONFIG.require(t);
        r instanceof Promise ? r.then((function() {
          return e.checkLoad()
        })).catch((function(r) {
          return e.failed("Can't load \"" + t + '"\n' + r.message.trim())
        })) : this.checkLoad()
      } catch(t) {
        this.failed(t.message)
      }
    }, 
    t.prototype.loadScript = function(t) {
      var e = this,
        r = document.createElement("script");
      r.src = t, r.charset = "UTF-8", r.onload = function(t) {
        return e.checkLoad()
      }, 
      r.onerror = function(r) {
        return e.failed("Can't load \"" + t + '"')
      }, 
      document.head.appendChild(r)
    }, 
    t.prototype.loaded = function() {
      var t, e, r, n;
      this.isLoaded = !0, this.isLoading = !1;
      try {
        for(var o = i(this.dependents), s = o.next(); !s.done; s = o.next()) {
          s.value.requirementSatisfied()
        }
      } 
      catch(e) { t = { error: e } } 
      finally {
        try { s && !s.done && (e = o.return) && e.call(o) } 
        finally { if(t) throw t.error }
      }
      try {
        for(var a = i(this.provided), l = a.next(); !l.done; l = a.next()) {
          l.value.loaded()
        }
      } 
      catch(t) { r = { error: t } } 
      finally {
        try { l && !l.done && (n = a.return) && n.call(a) } 
        finally { if(r) throw r.error }
      }
      this.resolve(this.name)
    }, 
    t.prototype.failed = function(t) {
      this.hasFailed = !0, this.isLoading = !1, this.reject(new c(t, this.name))
    }, 
    t.prototype.checkLoad = function() {
      var t = this;
      ((l.CONFIG[this.name] || {}).checkReady || function() {
        return Promise.resolve()
      })().
      then((function() {
        return t.loaded()
      })).
      catch((function(e) {
        return t.failed(e)
      }))
    }, 
    t.prototype.requirementSatisfied = function() {
      this.dependencyCount && (this.dependencyCount--, this.canLoad && this.load())
    }, 
    t.prototype.provides = function(e) {
      var r, n;
      void 0 === e && (e = []);
      try {
        for(var o = i(e), s = o.next(); !s.done; s = o.next()) {
          var a = s.value,
            c = t.packages.get(a);
          c || 
          (l.CONFIG.dependencies[a] || 
          (l.CONFIG.dependencies[a] = []), 
          l.CONFIG.dependencies[a].push(a), 
          (c = new t(a, !0)).isLoading = !0), 
          this.provided.push(c)
        }
      } 
      catch(t) { r = { error: t } } 
      finally {
        try { s && !s.done && (n = o.return) && n.call(o) } 
        finally { if(r) throw r.error }
      }
    }, 
    t.prototype.addDependent = function(t, e) {
      this.dependents.push(t), e || this.checkNoLoad()
    }, 
    t.prototype.checkNoLoad = function() {
      var t, e;
      if(this.noLoad) {
        this.noLoad = !1;
        try {
          for(var r = i(this.dependencies), n = r.next(); !n.done; n = r.next()) {
            n.value.checkNoLoad()
          }
        } 
        catch(e) { t = { error: e } } 
        finally {
          try { n && !n.done && (e = r.return) && e.call(r) } 
          finally { if(t) throw t.error }
        }
      }
    }, 
    t.packages = new Map, t
  }();
  e.Package = u
},

 長い関数だけど、関数を呼び出した時に実行されるのは、ほとんどが関数の定義だけされる感じ。でもどんな処理をする関数かは眺めてみる。定義されるのは n → i → s → a → Object.defineProperty → e.Package → var l → var c → e.PackageError → var u (膨大な tのメンバ関数 を定義する関数) → e.Package という順。それぞれどんな関数か見ていきます。 前の項目で確認した部分も出てきます。265 自体は前の235番号関数定義の中で呼ばれるので、その関数で使われる部分もありました。__webpack_modules__[235].call の中で __webpack_modules__[265].callが呼ばれています。__webpack_require__(265)がその後よばれたときには、export{ 265:{}} というような既に実行したという形跡を残す処理をします。


n

 for文のところが先に呼ばれる。t と e は以下のような値です。まず e から

e =
{
  name: 'Error'
  stackTraceLimit: 10
}
t=
{
  name: 'e'
  function(e, r) {var n = t.call(this, e) || this;return n.package = r, n}
}

 この n の関数は return として 3個のfunction(t,e) の関数をもっています。{__proto__: []} が 配列 なら 1つめの関数t.__proto__に eを格納して、2つめの関数で e の要素をひとつづつ取り出して、r に格納しながら hasOwnProperty.call(e, r) を実行します。そして呼び出された引数の t[r] に e[r] を格納します。そうやって再帰的に n の関数を実行します。3つめの関数で e の形式が function でもなく null でもないなら例外を発生させて、Error のときに実行される catch引数に if("function" != typeof e && null !== e) throw new TypeError("Class extends value " + String(e) + " is not a constructor or null"); を渡して実行します。3つ目の関数の最後に関数 r を t を返すようなthis.constructor を設定してます。また再帰的に n を処理しようとするカンマ構文があって、最後に e が null なら Object を新規に生成し、違えば rを返す関数のメンバ関数の r.prototype に e.prototype の内容を格納する。

 

i

 i は Itratorを作成する関数です。

 

s

 s に渡される t は ['input/tex-base'] → ['input/tex-base', '[tex]/ams'] → ['input/tex-base', '[tex]/newcommand'] → ['input/tex-base', '[tex]/noundefined'] → ['input/tex-base', '[tex]/require'] → ['input/tex-base', '[tex]/require', '[tex]/autoload'] → ['input/tex-base', '[tex]/newcommand', '[tex]/configmacros'] → ['input/tex-base', '[tex]/newcommand']のような配列です。e は undefined とかです。


 s に t の値をプッシュするような関数です。265関数内のt.prototype.makeDependenciesという部分で処理されます。

 

a

 a に渡される引数 t, e, r は t が []、 e は ['input/tex-base'] → ['input/tex-base', '[tex]/ams'] → ['input/tex-base', '[tex]/newcommand'] → ['input/tex-base', '[tex]/noundefined'] → ['input/tex-base', '[tex]/require'] → ['input/tex-base', '[tex]/require', '[tex]/autoload'] → ['input/tex-base', '[tex]/newcommand', '[tex]/configmacros'] → ['input/tex-base', '[tex]/newcommand']、r は flase のような値です。e の値を t にコピーして結合していくような関数です。

 

Object.defineProperty

 実行すると e の __esModule が true になります。{PackageError: undefined, Package: undefined, __esModule: true}

 

e.Package

 e.Package は undefined になる。  

var l

 l は、以下のような値になります。

{
 Package: undefined,
 PackageError: undefined,
 PathFilters: undefined,
 Loader: undefined,
 MathJax: undefined,
 CONFIG: undefined,
}

 

var c

 は、今のサンプルだと呼ばれないね。  

e.PackageError

 

var u

 u の中で呼ばれる関数はいかのようなモノ。


function t(e, r) {
  void 0 === r && (r = !1), 
  this.isLoaded = !1, 
  this.isLoading = !1, 
  this.hasFailed = !1, 
  this.dependents = [], 
  this.dependencies = [], 
  this.dependencyCount = 0, 
  this.provided = [], 
  this.name = e, 
  this.noLoad = r, 
  t.packages.set(e, this), 
  this.promise = this.makePromise(this.makeDependencies())
}

 で、このときの e は 'loader' です。r は、true です。

this.makeDependencies は、この u の中で定義される関数で以下のようなモノです。

l.CONFIG.dependencies.hasOwnProperty(u) ? 
  p.push.apply(p, a([], s(l.CONFIG.dependencies[u]), !1)) 
:
  "core" !== u && p.push("core");
  try {
    for(var h = i(p), f = h.next(); !f.done; f = h.next()) {
      var d = f.value,
        m = o.get(d) || new t(d, c);
      this.dependencies.indexOf(m) < 0 && 
      (
        m.addDependent(this, c), 
        this.dependencies.push(m), 
        m.isLoaded || 
        (this.dependencyCount++, n.push(m.promise))
      )
    }
  } catch(t) {
    e = {
      error: t
    }
  } finally {
    try {
      f && !f.done && (r = h.return) && r.call(h)
    } finally {
      if(e) throw e.error
    }
  }
  return n
}

 この u という引数には 'core' → 'startup' とかという値が入ります。core のときは、判定式が false なので push 処理はされず、p が空ならば何も処理されません。startupのときは p が ['core'] になります。繰り返しの処理の個別の値で d が 'core' になって、


 t.packages.set(e, this); → o = t.packages → o.get(d = 'core') で c = this.noLoad = true; m = o.get(d) || new t(d, c); t.package.get('core') があれば、 m = new t('core', true) を実行します。 Promiseのcoreの登録がされる感じでしょうか。


 t.prototype.makeDependencies を this とし、 Dependents値にPromiseの状態に関する値を構築しています。Promiseに登録した個数も管理しています。

return

Object.defineProperty
Object.defineProperty(t.prototype, "canLoad", {
  get: function() {
    return 
    0 === this.dependencyCount && 
    !this.noLoad && 
    !this.isLoading && 
    !this.hasFailed
  },
  enumerable: !1,
  configurable: !0
})


 DefineProperty は 3つの引数をとります。 1.操作するオブジェクト名 t.prototype、2.プロパティ値 canLoad 3.データ記述子 enumerable configurable やアクセサー記述子 get です。get には関数が定義されています。this.dependencyCount が 0 なら !this.noLoad 値の true を、それも flase なら、次を返す。といった関数です。


 

t.resolvePath

 235の関数のcheckVersion関数から呼び出されます。

t.resolvePath = function(t, e) {
  void 0 === e && (e = !0);
  var r = {
    name: t,
    original: t,
    addExtension: e
  };
  return l.Loader.pathFilters.execute(r), r.name
},


 実行されるときの t は 'core' のような値。e は undefined のような値になっています。eが undefined のとき e = !0 で trueとなり r = {neme: 'core', original: 'core', addExtension: true} で、これを引数として l.Loader.pathFilters.executeを呼び出します。返却値は r.name なので 'core' です。



 execute の内容は以下のようなものです。


e.prototype.execute = function() {
  for(var t, e, r = [], n = 0; n < arguments.length; n++) r[n] = arguments[n];
  try {
    for(var o = i(this), l = o.next(); !l.done; l = o.next()) {
      var c = l.value,
        u = c.item.apply(c, a([], s(r), !1));
      if(!1 === u) return !1
    }
  } catch(e) {
    t = {
      error: e
    }
  } finally {
    try {
      l && !l.done && (e = o.return) && e.call(o)
    } finally {
      if(t) throw t.error
    }
  }
  return !0
}


 関数名の次の引数リストで変数名が付与されていないので、argument から取り出します。r[n] に保持します。繰り返し処理の個別の値は以下のような値です。i(this) → {item: ƒ function(t) {return e.CONFIG.source.hasOwnProperty(t.name) && (t.name = e.CONFIG.source[t.name]), !0 }, priority: 0} この関数を c.item として、a([], s(r), !1) = [ name:'core', original: 'core', addExtension: true ] で t.name も [ name:'core', original: 'core', addExtension: true ]です。この値を e.CONFIG.sourceのメンバ値として保持させます。次の値は{name: '[mathjax]/startup.js', original: 'startup', addExtension: true}のような値になります。 ]


 戻った関数で r が以下のような値になりますので、このような構造を得るのが目的なのだろうと思います。

{name: 'file:///C:/MathJax/es5/startup.js', original: 'startup', addExtension: true}


 ん?startup.jsって何を受け持つファイルなんだろうな。あーなるほど。本来は全てはstartup.jsを呼び出す方式を使うのが普通なんだな。自分らが使っているtex-mml-chtmlとかは、出力の形式とかを設定しないで呼び出す楽々セットなんだな。だから基本的には、楽々セットの起動URLを使ってもstartup.jsは呼び出そうとするんだろう。楽々セットの癖に5万行になっているのはかなり独立してるんだろうね。MathJaxのそもそものオプション機能の多さについても理解しておいた方がよいのかもしれない。単純に数式をHTMLにするだけの機能ではないからね。SVGにもできれば、数式番号のリセットやら追加の描画呼び出しといったこともできるし、描画処理がどこまで進んだからで呼び出せる関数もあるみたい。でも、自分は、全貌を見ずに先頭から見ていく。

 

t.loadAll

 以下のような関数です。


t.loadAll = function() {
  var t, e;
  try {
    for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) {
      var o = n.value;
      o.canLoad && o.load()
    }
  } catch(e) {
    t = {
      error: e
    }
  } finally {
    try {
      n && !n.done && (e = r.return) && e.call(r)
    } finally {
      if(t) throw t.error
    }
  }
}


 この関数の繰り返し部で得られる個別の値はものすごく大きい配列です。

 とはいいつつも、

name: "[tex]/action",
name: "[tex]/ams",
name: "[tex]/autoload",
name: "[tex]/configmacros",
name: "[tex]/newcommand",
name: "[tex]/noundefined",
name: "[tex]/require",
name: "a11y/assistive-mml",
name: "core",
name: "input/mml",
name: "input/tex",
name: "input/tex-base",
name: "loader",
name: "output/chtml",
name: "output/chtml/fonts/tex.js",
name: "startup"
name: "ui/menu",

 のような値のそれぞれに isLoaded: true, isLoading: false, hasFailed: false, dependents: dependencies: provided: [[Circular],…, dependencyCount: 0, provided: [resolve: function () { [native code] }, reject: function () { [native code] },promise: { … といったような構造を持った値です。


 a11y は accessibility の間を数字に置き換えた。a11yという表現です。こういう表現と言うのはいくつかあります。i18nとかね。こういうのをヌメロニムというそうで。以下のようなものが代表的です。

  • a11y - Accessibility(利用しやすさ)[2]
  • c14n - Canonicalization(正準,正規化)[3]
  • d11n - Documentation(文書化)[4]
  • G11n - Globalisation / Globalization(世界化)[5][6]
  • i18n - Internationalisation / Internationalization(国際化)[1][5][6]
  • i14y - Interoperability(相互運用性)[7]
  • K8s - Kubernetes
  • L10n - Localisation / Localization(地域化)[5][6]
  • m17n - Multilingualisation / Multilingualization(多言語化)[5]
  • n11n - Normalisation / Normalization(正規化)[8]
  • P13n - Personalisation / Personalization(個人化)
  • P45 - Pneumonoultramicroscopicsilicovolcanoconiosis
  • tr8n - Translation(翻訳)[9]
  • v12n - Virtualisation / Virtualization(仮想化)
  • D34n - Demand response based resource provision


 

t.prototype.makeDependencies

 

t.prototype.makePromise

 

t.prototype.load

 

t.prototype.loadCustom

 

t.prototype.loadScript

 

t.prototype.loaded

 

t.prototype.failed

 

t.prototype.requirementSatisfied

 

t.prototype.addDependent

 

t.prototype.checkNoLoad

 

ページ

 

関連情報

 MathJax

 

VScodeで簡易WebServerの元でデバッグに戻る。