點燈坊

失くすものさえない今が強くなるチャンスよ

如何使 fetch 回傳 Future ?

Sam Xiao's Avatar 2021-07-25

fetch 為 Browser 內建的 HTTP Client 能回傳 Promise,可藉由 encaseP 加以改造回傳 Future。

Version

Fluture 14.0.0

fetch

import { create, env } from 'sanctuary'
import { encaseP, fork } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
import fetch from 'node-fetch'

let { pipe, map, prop, unchecked: { chain }} = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let url = 'https://jsonplaceholder.typicode.com/todos/1'

pipe ([
  encaseP (fetch),
  chain (encaseP (x => x.json())),
  map (x => x.title),
  fork (error) (log)
]) (url)

使用 pipe 組合 IIFE:

  • encaseP (fetch):使 fetch 回傳 Future
  • chain (encaseP (x => x.json())):使 x => x.json() 回傳 Future,因爲也回傳 Future,故需使用 chain 綁定
  • map (x => x.title):從 Future 內取出 title
  • fork (error) (log):解開 Future

fetch000

Point-free

import { create, env } from 'sanctuary'
import { encaseP, fork } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
import fetch from 'node-fetch'

let { pipe, compose, map, prop, unchecked: { chain }} = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let url = 'https://jsonplaceholder.typicode.com/todos/1'

let toJson = encaseP (x => x.json())

pipe ([
  encaseP (fetch),
  chain (toJson),
  map (prop ('title')),
  fork (error) (log)
]) (url)

11 行

let toJson = encaseP (x => x.json())

使用 encasePx => x.json() 轉成回傳 Future 的 toJson

13 行

pipe ([
  encaseP (fetch),
  chain (toJson),
  map (prop ('title')),
  fork (error) (log)
]) (url)
  • chain (toJson):因為 toJson 回傳 Future,故需使用 chain 將 Future 與 toJson 綁定
  • map (prop ('title')):使用 prop 使 map 能 Point-free

fetch001

Conclusion

  • fetch 的關鍵在於 fetch 會先回傳一次 Promise,x => x.json() 再回傳第二次 Promise,這在 then 無感,因為 Promise 的 then 兼具 mapchain,但在 Future 就必須明確使用 chain
  • 因為 Quokka 基於 Node,因此使用 node-fetch 所提供的 fetch,在 browser 可直接使用 fetch

Reference

Fluture, encaseP