我的理論是這樣的行爲是Node.js的require
緩存是如何工作的,節點如何處理週期性的依賴,以及一些關於組合如何加載.coffee
文件直入節點時transpiler工作的咖啡。
我做了不同的咖啡腳本和JavaScript版本的程序與說明性日誌記錄如下。我用「maincs」和「mainjs」來確保這兩種語言沒有混合。
mainjs.js
console.log("mainjs starting");
console.log("mainjs exporting name");
module.exports = {
name: 'John'
};
console.log("mainjs requiring configjs");
var configjs = require('./configjs');
console.log("mainjs calling configjs.hello()");
configjs.hello();
configjs.js
console.log("configjs starting");
console.log("configjs requiring mainjs");
var mainjs = require("./mainjs");
console.log("configjs exporting hello");
module.exports = {
hello: function() {
return console.log("hello " + mainjs.name);
}
};
maincs.coffee
console.log "maincs starting"
console.log "maincs exporting name"
module.exports =
name: 'John'
console.log "maincs requiring configcs"
configcs = require './configcs'
console.log "maincs calling configcs.hello()"
configcs.hello()
configcs.coffee
console.log "configcs starting"
console.log "configcs requiring maincs"
maincs = require "./maincs"
console.log "configcs exporting hello"
module.exports =
hello: ->
console.log "hello #{maincs.name}"
所以,當我們運行它們,我們得到不同的輸出(正如你所看到的)。我在下面突出了有趣的一點。
node mainjs.js
mainjs starting
mainjs exporting name
mainjs requiring configjs
configjs starting
configjs requiring mainjs #<--- Note the top-level mainjs.js code does not re-execute
configjs exporting hello
mainjs calling configjs.hello()
hello John
coffee maincs.coffee
maincs starting
maincs exporting name
maincs requiring configcs
configcs starting
configcs requiring maincs
maincs starting # <-- Look, the top-level maincs.coffee code is re-executing
maincs exporting name
maincs requiring configcs
maincs calling configcs.hello()
TypeError: Object #<Object> has no method 'hello'
因此,我認爲這種行爲與Node.js的如何要求系統模塊緩存作品和transpile上即時CoffeeScript的解釋做。基本上,如果maincs = require "maincs"
導致重新執行maincs
模塊中的頂級代碼,那麼我們會遇到循環依賴情況,此時節點將提供未完成的configcs
exports對象副本。
請閱讀node.js documentation on cyclic dependencies that explains this behavior(至少部分)。
現在,有趣的一點是,如果你確保你需要maincs
前hello
功能輸出,你可以逃脫這個部分。但是,從hello
代碼中引用main.name
將不起作用,因爲在第一次執行時,main將是未定義的。
maincs2.coffee
console.log "maincs2 starting"
console.log "maincs2 exporting name"
module.exports =
name: 'John'
console.log "maincs2 requiring configcs2"
configcs2 = require './configcs2'
console.log "maincs2 calling configcs2.hello()"
configcs2.hello()
configcs2.coffee
console.log "configcs2 starting"
console.log "configcs2 exporting hello"
module.exports =
hello: ->
console.log "hello from configcs"
console.log "configcs2 requiring maincs2"
maincs2 = require "./maincs2"
coffee maincs2.coffee
maincs2 starting
maincs2 exporting name
maincs2 requiring configcs2
configcs2 starting
configcs2 exporting hello
configcs2 requiring maincs2
maincs2 starting
maincs2 exporting name
maincs2 requiring configcs2
maincs2 calling configcs2.hello()
hello from configcs
maincs2 calling configcs2.hello()
hello from configcs
所以基本上,這種行爲是組合兩個模塊是如何被require
緩存, 怎麼樣 與週期性依賴關係相互作用,以及咖啡譯者本身的某些方面。請注意,將.coffee轉換爲.js並使用節點執行可以避免在使用IIFE包裝器的普通coffeescript和沒有包裝器的普通coffeescript中出現此問題,因此IIFE包裝器似乎並不重要(無論如何,節點基本上都會自行添加)。
afaik咖啡腳本始終要在執行前進行編譯。 – Amberlamps
它的確如此,但是使用npm install -g coffee-script免費獲得的'咖啡'應用產生了上述行爲 - 我試圖避免每次我想測試開發代碼更改時的編譯週期 –