iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
1
Software Development

Functional Programming in JS系列 第 8

Buzz word 4 : Stateless

準確一點應該是 Stateless function,更語意一點就是 Avoid Shared State,因為一個系統中不太可能全部都是 Stateless 的,還是要有地方存這些狀態。

Stateless is any variable, object, or memory space that exists in a shared scope, or as the property of an object being passed between scopes.

shared scope 可以包含在 global scope 或是 function scope (恩,其實 JS 總共也才這兩個 scope)。

以前很習慣 Shared state (Stateful),不管是 global scope 裡的變數或增加/減少 object 裡的屬性。

// words = ['world', 'fp', 'to', 'welcome']
let keepers = []
 
for(let i in words) {
   if(words[i].length > 3) {
     keepers.push(words[i])
   }  // ['world', 'welcome']
}
// 程式大家一起 Share keepers 這個 Array 

Shared state 最大問題就是你必須很清楚每一行程式碼在做什麼,什麼時候做了什麼事變動了 state,並且要記憶 state 變成多少 。一但系統變複雜或是有多個工程師共同開發就必須花大量時間去弄懂程式碼在幹嘛 (崩潰狀)

// Stateful
const x = 4; 
x++; // x 變 5
// 省略 100 行...

x*2 // 完全不知道哪行改過 x,現在到底變成什麼
 

https://ithelp.ithome.com.tw/upload/images/20200908/20106426JMEtcqgfQ8.jpg
若還加上 promise 、setTimeout 的運算更難掌握處理 State 的先後次序 (就像上圖中 state 並不是獨立存在而是互相依賴在別的運算或函式中); 但若改成 FP 習慣的 Stateless function,你完全不用去記憶 state 到底是什麼,因為他只存在單一函數中,執行完 state 就被丟掉了

// Stateless
 _.filter(x => x.length > 3),  // 不用記憶 x 是什麼

另外一個缺點是 Share State 會有順序與執行次數問題

const x = {
  val: 2
};

const x1 = () => x.val += 1;

const x2 = () => x.val *= 2;

x2();
x1();

console.log(x.val); // 5

x2();
x1();
console.log(x.val); // 11

以上範例會發現執行次數影響結果,那改成 Shareless 呢

const x = {
  val: 2
};

const x1 = x => Object.assign({}, x, { val: x.val + 1});
const x2 = x => Object.assign({}, x, { val: x.val * 2});

console.log(x1(x2(x)).val); // 5

x2(x);
x1(x);
// 那順序改變呢
console.log(x1(x2(x)).val); // 5

就會發現不管執行幾次結果都還是一樣

這一篇比較簡短一點(我不會說出來,其實是文章庫存都被我用完了 orz),由範例可以看到 Share State 通常資料也會是 Immutable 的,然後 Immutable data 又容易產生無法預期的 Side Effect,這一些 Buzz Words 其實都是環環相扣的啊


參考文章

如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。


上一篇
把 Mutable array/object 轉成 Immutable
下一篇
Buzz word 5 : Pure Function
系列文
Functional Programming in JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
iT邦新手 2 級 ‧ 2022-04-05 20:03:10

嗨~
以下一些我的看法,供參考:

在改成 Shareless 那個部分的這註解 // 那順序改變呢 看起來怪怪的。
在想那個範例比較像是在說明:「不管執行幾次都一樣」。


順序的問題比較像以下兩者的差異:

Shared State:

  const x = { val: 2 }

  const x1 = () => (x.val += 1)
  const x2 = () => (x.val *= 2)

  const a = (() => {
    x2()
    x1()
    return x.val
  })()

  const b = (() => {
    x2()
    x1()
    return x.val
  })()

  console.log(a, b) // 5 11
  const x = { val: 2 }

  const x1 = () => (x.val += 1)
  const x2 = () => (x.val *= 2)

  const b = (() => {
    x2()
    x1()
    return x.val
  })()

  const a = (() => {
    x2()
    x1()
    return x.val
  })()

  console.log(a, b) // 11 5

Stateless:

  const x = { val: 2 }

  const x1 = (x) => Object.assign({}, x, { val: x.val + 1 })
  const x2 = (x) => Object.assign({}, x, { val: x.val * 2 })

  const a = (() => x1(x2(x)).val)()
  const b = (() => x1(x2(x)).val)()

  console.log(a, b) // 5 5
  const x = { val: 2 }

  const x1 = (x) => Object.assign({}, x, { val: x.val + 1 })
  const x2 = (x) => Object.assign({}, x, { val: x.val * 2 })

  const b = (() => x1(x2(x)).val)()
  const a = (() => x1(x2(x)).val)()

  console.log(a, b) // 5 5

我要留言

立即登入留言