这最初是David Nolen在Slack上关于https://clojurians.slack.com/archives/C07UQ678E/p1644422895167709的讨论。
现在似乎都有一个常见的模式,就是依赖于JS互操作语法以及^js
。当编译器警告用户“无法推断目标类型”时,用户会使用这些语法。同时,在JS对象和数组上使用内建的CLJS函数和宏(如first
、seq
、when-first
等)也不是不常见,因为这些支持是明确存在的。
这导致了一个问题,使得它极其容易在优化的构建中引入问题,这些问题是无法防御的,除非你把`^js`放在每个进行JS互操作的地方。
特别是在代码很重的互操作代码中尤其如此,例如
(defn replace-track-source! [^js playlist track-name src]
(loop [tracks (.-tracks playlist)]
(when-first [^js track tracks]
(if (= (.-name track) track-name)
(-> (to-audio-buffer src playlist)
(.then (fn [audio-buffer]
(let [audio-buffer (audio-util/normalize-volume audio-buffer)]
(set! track -src audio-buffer)
(.setBuffer track audio-buffer)
(.setCues track 0 (.-duration audio-buffer))
(.setPlayout track (doto (Playout. (.-ac playlist) audio-buffer)
(.setVolumeGainLevel (.-gain track))
(.setStereoPanValue (.-stereoPan track))))
(.calculatePeaks track (.-samplesPerPixel playlist) (.-sampleRate playlist))
(.adjustDuration playlist)
(.drawRequest playlist)))))
(recur (next tracks))))))
上面的例子有问题,因为编译器不会警告你在`track`绑定之前省略了^js
。但如果没有这个标签,所有在`track`上调用函数的名称都会被压缩。
一个可能的解决方案是在CLJS函数使用`^js`标签未保留的情况下,引入一个可选的警告。