Angular 上用 MathJax 的一些問題

首發於 Eliseos:我是如何解決 Angular 上用 MathJax 的一些問題的 - Eliseos


話說我本來是傾向於 KaTeX 的,因為我感覺他很快,而且 MathJax 似乎很難配。但是大家表示對缺少功能的 KaTeX 並無好感,給我提供了一些鑽研 MathJax 的動力。

其實也不算鑽研,因為實際上 MathJax 很簡單,調用 MathJax.Hub.Queue([Typeset, MathJax.Hub, this.element.nativeElement]); 就可以渲染一個元素(這個 this.element.nativeElement 是從 Angular 中調用它 DOM 的語法),這個 .Queue 實際上是 MathJax 自己實現的回調格式,語法非常清奇,參數個數不定,每個都是數組,代表一個回調,順序執行。比如這個 [Typeset, MathJax.Hub, this.element.nativeElement],第一個元素是方法名,第二個元素是 this,之後的元素都是參數……

我們可以看到這個就相當於執行 MathJax.Hub.Typeset(this.element.nativeElement),那為啥不執行這個?因為這方法是同步的,會導致頁面十分卡。於是 MathJax 就自己封裝了一個非同步隊列(它的 API 可能幾百年沒改了)

我們說回 Angular。因為要用 markdown,我的思路是用 marked 封裝一個 directive。那麼我們就應該在 marked 渲染完成之後用 MathJax 去 Typeset 這個組件。但真的這樣做了,卻產生了奇妙的效果——切換頁面之後,要等將近一分鐘才開始渲染。我在它的隊列里放了幾個 log,發現每個元素都被 queue 了 4 次,幾十個元素,難怪要一分鐘才開始渲染下一頁的內容,即使大部分 markdown 裡面根本沒有數學。

這時候我開始灰心了,這個問題就沒有解決辦法了嗎?絕望之時,我想到能不能直接 Typeset document,結果是可以的,而且十分快。所以渲染並不慢,可能是渲染的初始化過程比較慢。那麼這時候方案就出來了,我們可以盡量減少渲染次數,同時只渲染 document。只要這個渲染還在進行,那麼有再多的元素 queue 上來,我們也只當作 queue 了一次。

於是我就寫了這麼個 service:

@Injectable()nexport class MathjaxService {nn public isQueued = false;n public isRunning = false;n window: any;nn constructor(@Inject(PLATFORM_ID) private platformId: Object) {n if (isPlatformBrowser(this.platformId)) {n this.window = window as any;n }n }nn finishRunning() {n this.isRunning = false;n if (this.isQueued) {n this.queueChange();n }n }nn queueChange() {n if (this.isRunning) {n this.isQueued = true;n } else {n this.isQueued = false;n this.isRunning = true;n if (isPlatformBrowser(this.platformId)) {n if (this.window.MathJax) {n this.window.MathJax.Hub.Config({n messageStyle: none,n tex2jax: {n // preview: none,n inlineMath: [[$, $]],n processEscapes: truen }n });n this.window.MathJax.Hub.Queue([log, console, start], [Typeset, this.window.MathJax.Hub, document], [log, console, end], [finishRunning, this]);n }n } else {n this.finishRunning();n }n }n }n}n

事實證明,它能圓滿完成任務,它也就是現在運行在這個網站上的代碼。


推薦閱讀:

【從複數開始的科技文明II】- 文化脈絡中的數學 10
一些簡單的小問題
Stephen Wolfram:《一種新科學》15周年回顧

TAG:Angular? | MathJax | 数学 |