這是一個被一年前的自己坑的故事…
這是最近在重構自己一年前寫的code時,發現的一個技術債也蠻有趣的,所以就把它記錄下來,希望能幫助到跟我遇到一樣問題的人,解決你心中的WTF。
遇到的問題是什麼?
這篇文章我也不想寫的太長,所以就簡單敘述一下情境吧,當時的情境是這樣的…
重構到某個js檔案時,打上
const constants = require('./constants')
時發現,為什麼constants
變數是empty object{}
!?我明明有做module.exports
啊啊啊??
原因到底是什麼?
其實遇到這種問題有很多解決方法,比如像是直接在調用某個function時把constants傳進去就可以了,但找出源頭才是解決問題最好的方法,所以還是花了點時間在google searching上尋找答案,想瞭解到底是遇到啥鬼問題。
最後得到的答案是,Node本身對require的call有一個防呆的設計,就是只要developer寫出modules cycles的時候,就會自動幫你把還沒讀完的檔案export出一個「空」object。
也就是你有個a.js
requireb.js
,然後b.js
requirea.js
一直無限循環下去的感覺。
所以這就是為什麼會說這是技術債…完全就是一年前的自己寫的一份爛code然後坑了現在的自己…
什麼是modules cycles?
想直接看原文的人可以直接參考官方的文件連結,以下的解釋都是直接修改原文的範例,官方解釋的其實就很清楚了,這裡只是做個解說而已。https://nodejs.org/api/modules.html#modules_cycles
先來一段官方對這種問題的簡述
When there are circular
require()
calls, a module might not have finished executing when it is returned.
這裡來舉例個簡單的例子,假設我今天a.js是長這樣
// a.jsconst b = require('b.js')... do something ...module.exports = { name: 'A' }
然後有個b.js
// b.jsconst a = require('a.js')... do something ...module.exports = { name: 'B' }
最後我有個main.js來呼叫a.js
// main.jsconst a = require('a.js')
執行順序是
- main 呼叫 a.js
- a.js 呼叫 b.js
- b.js 呼叫 a.js …..
理論上這應該要是無限循環,但就跟前面提到的一樣,Node本身有做一個防呆,當走到第三步時,Node會發現b.js呼叫了還沒執行完的a.js,因為a.js還沒執行完,所以就索性回傳一個空的object給b.js,防止你進入無限循環。
簡單來說就是當你在require的檔案還沒被執行完成時,那Node就會返回一個空的object給你。
大概就是這樣~每次遇見問題都是成長的好機會,而且解決問題的那種成就感也算是當工程師的一種樂趣吧。
希望這篇文章能幫助跟我一樣遇到這個問題的人~