編程思想系列——使用函數副作用實現程序緩存設計

函數式編程裏面有一個重要的概念,純函數,即怎樣的輸入有怎樣的輸出,並且不依賴於外部變量,同時函數也不會產生任何可觀察的副作用。那麼什麼是函數副作用呢?

函數副作用是指函數在正常工作任務之外對外部環境所施加的影響。

具體地說,函數副作用是指函數被調用,完成了函數既定的計算任務,

1,但同時因爲訪問了外部數據,尤其是因爲對外部數據進行了寫操作,從而一定程度地改變了系統環境

2,函數的副作用也有可能是發生在函數運行期間,由於對外部數據的改變,導致了同步運行的外部函數受到影響。

總結:重要的一點是有沒有改變系統環境。

比如一個純函數在運行期間調用了另外一個純函數,雖然調用了外部變量,但是該函數仍然是純函數,因爲該函數並沒有改變系統環境。

什麼是可觀察的副作用:

在函數內部與其外部的任意交互。這可能是在函數內修改外部的變量

常見的副作用實例:

  • 進行一個 HTTP 請求

  • Mutating data

  • 輸出數據到屏幕或者控制檯

  • DOM 查詢/操作

  • Math.random()

  • 獲取的當前時間

副作用的意義

副作用從名字上看似乎是不好的,但是實際應用中副作用有很大的意義。

在探討副作用的意義之前,我們先來看下純函數的意義。

1,函數式編程中大量使用純函數

函數式編程可以接收函數作爲入參,並且可以返回函數,從代碼的可維護性上講,函數式編程最大的好處是引用透明,即函數運行的結果只依賴於輸入的參數,而不依賴於外部狀態

函數式編程的精髓:業務系統模型無狀態。模型的好壞,直接影響到代碼的正確性、可靠性、穩定性,以及是否需要996。

2,方便代碼重構

由於純函數只和入參有關,這時候重構該函數時對系統幾乎沒有影響

3,方便測試,可預測性增強,降低代碼管理的難度

不需要考慮上下文,只考慮輸入輸出

4,健壯性

改變純函數的執行次序,並不會對結果造成影響

實例:redux的reducer出=純函數

reducer每次返回一個新的狀態,而不是去改變舊的狀態,避免了對象的深比較,而深比較是比較昂貴的。

與之相對的是函數副作用

函數副作用的良性意義:

1,通過指針和引用參數,主動讓被調函數獲得外部數據訪問權,以便提高數據處理的性能,比如實現緩存機制

2,改變全局變量,比如計數,根據全局變量的不同的值,調用不同的接口

3,通過返回指針或引用的做法,獲得共享堆空間,以簡化計算工作。

緩存設計實例:

比如,有函數getRseource(path)根據獲得資源,如果沒有副作用,每次都要執行存儲,有了副作用之後(外部變量),就可以簡化操作

  var UtilFiles; 
  getFileList: function(path) {
    if (UtilFiles) return UtilFiles;
    if (!fs.existsSync(path)) {
      throw new Error("can't find pages directory.");
    }
    var files = fs.readdirSync(path);
    if (!files || files.length === 0) {
      throw new Error("can't find any page");
    }
    files = files.filter(function(f) {
      return fs.existsSync(pageDir + "/" + f + "/app.js");
    });
    if (files.length === 0) {
      throw new Error("can't find any page");
    }
    UtilFiles = files;
    return files;
  },

說明:

  • 通過var創建的全局變量(任何函數之外的程序中創建)是不能被刪除的。
  • 無var創建的隱式全局變量(無視是否在函數中創建)是能被刪除的。

隱式全局變量並不是真正的全局變量,但它們是全局對象的屬性

參考:https://baike.baidu.com/item/%E5%87%BD%E6%95%B0%E5%89%AF%E4%BD%9C%E7%94%A8/22723425?fr=aladdin

https://www.liaoxuefeng.com/article/1260118907809920​​​​​​​

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章