函數(shù)式編程

#### 函數(shù)式編程

#### 函數(shù)式編程總結(jié)

1. 認(rèn)識(shí)函數(shù)式編程

2. 函數(shù)復(fù)習(xí)

? ? (1)函數(shù)是一等公民

? ? (2)高階函數(shù)

? ? (3)閉包

3. 函數(shù)式編程基礎(chǔ)

? ? (1)lodash

? ? (2)純函數(shù)

? ? (3)柯里化

? ? (4)管道

? ? (5)函數(shù)組合

4. 函子

? ? (1)Functor

? ? (2)MayBe

? ? (3)Either

? ? (4)IO

? ? (5)Task(folktale)

? ? (6)Monad

#### 認(rèn)識(shí)函數(shù)式編程

1. 隨著React的流行收到越來愈多的關(guān)注, React高階組件使用函數(shù)式編程實(shí)現(xiàn)

2. Vue 3 開始擁抱函數(shù)式編程

3. 函數(shù)式編程可以拋棄this

4. 打包過程中可以更好的利用tree-shaking過濾無用代碼

5. 方便測(cè)試, 方便處理

6. 更多生態(tài)庫進(jìn)行函數(shù)式開發(fā): lodash、 underscore、ramda

#### 函數(shù)式編程概念

1. FP是編程范式之一? (面向過程、面向?qū)ο缶幊?

2. 面向?qū)ο缶幊痰乃季S方式: 把現(xiàn)實(shí)世界中的事物抽象成程序世界中的類和對(duì)象, 通過封裝、繼承、多態(tài)來演示事物事件的聯(lián)系

3. 函數(shù)式編程的思維方式: 把現(xiàn)實(shí)世界的事物和事物之間的聯(lián)系抽象到程序世界(對(duì)運(yùn)算過程進(jìn)行抽象)

? 程序本質(zhì): 根據(jù)輸入通過某種運(yùn)算獲得相應(yīng)的輸出

? 函數(shù)式編程中的函數(shù)是數(shù)學(xué)中的函數(shù)即映射關(guān)系

? 相同的輸入始終得到相同的輸出(純函數(shù))

? 函數(shù)式編程用來描述數(shù)據(jù)(函數(shù))之間的映射

#### 函數(shù)復(fù)習(xí)

#### 函數(shù)是一等公民 First-class Function

1. 函數(shù)是一個(gè)普通對(duì)象: 可以存儲(chǔ)到變量/數(shù)組中, 可以作為另一個(gè)函數(shù)的參數(shù)和返回值, 可以通過new Function()構(gòu)造一個(gè)新函數(shù)

****MDN中關(guān)于函數(shù)是一等公民的解釋只有三個(gè): (1)可以存儲(chǔ)于變量中(2)可以做為參數(shù)(3)可以作為返回值

****函數(shù)可以遞歸調(diào)用---不是函數(shù)是一等公民的佐證

2. 函數(shù)是一等公民是學(xué)習(xí)高階函數(shù)、柯里化的基礎(chǔ)

#### 高階函數(shù) Higher-order function

1. 函數(shù)可以作為參數(shù)傳遞給另一個(gè)參數(shù)

function forEach (array, fn){

? ? for(let i = 0;i < array.length; i++){

? ? ? fn(array[i])

? ? }

}

let arr = [1, 3, 4, 9, 10]

forEach(arr, function(item){

? ? console.log(item)

})

2. 函數(shù)可以作為一個(gè)函數(shù)的返回值

function makeFn(){

? ? let msg = 'Hello'

? ? return function(){

? ? ? ? console.log(msg)

? ? }

}

const fn = makeFn()

fn()

makeFn()()

#### 高階函數(shù)的意義

1. 抽象可以幫我們屏蔽細(xì)節(jié), 只需要關(guān)注于我們的目標(biāo)

2. 高階函數(shù)是用來抽象通用的問題

#### 常用的高階函數(shù) forEach map filter every some find/findIndex reduce等

// map

const map = (array, fn) => {

? ? let results = []

? ? for(let value of array){

? ? ? ? results.push(fn(value))

? ? }

? ? return results

}

let arr = [1,3, 4, 5]

arr = map(arr, item => item * item)

console.log(arr)

//every

const every = (array, fn) => {

? ? let result = true

? ? for(let value of array){

? ? ? ? result = fn(value)

? ? ? ? if(!result){

? ? ? ? ? ? break

? ? ? ? }

? ? }

? ? return result

}

let arr = [1, 3, 5, 5,6, 20]

let r = every(arr, v => v > 10)

console.log(r)

//some

const some = (array, fn) => {

? ? let result = false

? ? for(let value of array){

? ? ? ? result = fn(value)

? ? ? ? if(result){

? ? ? ? ? ? break

? ? ? ? }

? ? }

? ? return result

}

let arr = [1, 3, 5, 7]

let r = some(arr, v => v % 2 === 0)

console.log(r)

#### 閉包

1. 閉包: 函數(shù)和其周圍的狀態(tài)(詞法環(huán)境)的飲用捆綁在一起形成閉包;? 可以在另一個(gè)作用域中調(diào)用一個(gè)函數(shù)的內(nèi)部函數(shù)并訪問到趕海書的作用域中的成員

2. 閉包的本質(zhì): 函數(shù)在執(zhí)行的時(shí)候會(huì)放到一個(gè)執(zhí)行棧上, 當(dāng)函數(shù)執(zhí)行完畢之后會(huì)從執(zhí)行棧上移除, 但是堆上的作用域成員因?yàn)楸煌獠恳貌荒茚尫? 因此內(nèi)部函數(shù)依然可以訪問外部函數(shù)的成員

//案例一

function forEach (array, fn){

? ? for(let i = 0;i < array.length; i++){

? ? ? fn(array[i])

? ? }

}

let arr = [1, 3, 4, 9, 10]

forEach(arr, function(item){

? ? console.log(item)

})

//案例二

function makeFn(){

? ? let msg = 'Hello'

? ? return function(){

? ? ? ? console.log(msg)

? ? }

}

const fn = makeFn()

fn()

makeFn()()

#### 函數(shù)式編程基礎(chǔ)

#### 純函數(shù)

1. 相同的輸入永遠(yuǎn)會(huì)得到相同的輸出, **而且沒有任何可觀察的副作用**

? ? 副作用: 函數(shù)依賴于外部的轉(zhuǎn)臺(tái)就無法保證輸出相同, 就會(huì)帶來副作用

? ? 副作用來源:? (1) 配置文件

? ? ? ? ? ? ? ? (2) 數(shù)據(jù)庫

? ? ? ? ? ? ? ? (3) 獲取用戶的輸入

? ? ? ? --- 所有的外部交互都有可能代理副作用, 副作用也使得方法通用性下降, 不適合擴(kuò)展和可重用性,同時(shí)副作用會(huì)給程序中帶來安全隱患給程序帶來不確定性, 但是副作用不可能完全禁止, 僅能能控制他們?cè)诳煽胤秶鷥?nèi)發(fā)生

? ? ? ? --- 副作用讓函數(shù)變得不純

2. 函數(shù)式編程不會(huì)保留計(jì)算中間的結(jié)果, 所以變量時(shí)不可變的(無狀態(tài)的)

3. 我們可以吧藝哥函數(shù)的執(zhí)行結(jié)果交給另一個(gè)函數(shù)去處理

// slice? splice

slice 純函數(shù)

let array = [1, 3, 5,6,4]

console.log(array.slice(0, 3))

console.log(array.slice(0, 3))

console.log(array.slice(0, 3))

splice 不純函數(shù)

console.log(array.splice(0, 3))

console.log(array.splice(0, 3))

console.log(array.splice(0, 3))

// 求和純函數(shù)

function getSum (n1, n2){

? ? return n1 + n2

}

console.log(getSum(2, 4))

console.log(getSum(2, 4))

console.log(getSum(2, 4))

4. 純函數(shù)的好處:

? ? (1) 可緩存

? ? (2) 可測(cè)試

? ? (3) 并行處理

function getArea (r){

? ? console.log(r, 'r')

? ? return Math.PI * r * r

}

let getAreaWithMemery = _.memoize(getArea)

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

// 模擬 memoize方法實(shí)現(xiàn)

function memoize (fn){

? ? let cache = {}

? ? return function(){

? ? ? ? console.log(arguments[0], fn)

? ? ? ? let key = JSON.stringify(arguments)

? ? ? ? console.log(key, fn.apply(fn, arguments), 'key')

? ? ? ? cache[key] = cache[key] || fn.apply(fn, arguments)

? ? ? ? return cache[key]

? ? }

}

let getAreaWithMemery = memoize(getArea)

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

console.log(getAreaWithMemery(4))

#### 柯里化

1. **使用柯里化解決硬編碼的問題**

? ? ***當(dāng)一個(gè)函數(shù)有多個(gè)參數(shù)的時(shí)候先傳遞一部分參數(shù)調(diào)用他(這部分參數(shù)以后永遠(yuǎn)不變)

? ? ***然后返回一個(gè)新的函數(shù)接受剩余的參數(shù)返回結(jié)果

//柯里化演示

function checkAge(age){

? ? let min = 18

? ? return age >= min

}

//普通的純函數(shù)

function checkAge(min, age){

? ? return age >= min

}

console.log(checkAge(18, 20))

console.log(checkAge(18, 20))

console.log(checkAge(22, 20))

console.log(checkAge(24, 20))

// 函數(shù)柯里化

function checkAge(min){

? ? return function(age){

? ? ? ? return age >= min

? ? }

}

// ES6

let checkAge = min => (age => age >= min)

let checkAge18 = checkAge(18)

console.log(checkAge18(20))

console.log(checkAge18(22))

console.log(checkAge18(16))

2. lodash中的柯里化

? _.curry 功能: 創(chuàng)建一個(gè)函數(shù),該函數(shù)接受一個(gè)或多個(gè)func的參數(shù),如果func所需要的參數(shù)都被提供則執(zhí)行func并返回執(zhí)行的結(jié)果. 否則繼續(xù)返回該函數(shù)并等待接收剩余的參數(shù).

function getSum(a, b, c){

? ? return a + b + c

}

const curried = _.curry(getSum)

console.log(curried(2, 3, 5))

console.log(curried(2)(3, 5))

console.log(curried(2)(3)(2))

console.log(curried(2, 3)(2))

//柯里化案例

''.match(/\s+/g)

''.match(/\d+/g)

function match (reg, str){

? ? return str.match(reg)

}

const match = _.curry(function (reg, str){

? ? return str.match(reg)

})

const haveSpace = match(/\s+/g)

const haveNumber = match(/\d+/g)

console.log(haveSpace('hello'))

console.log(haveNumber('123456asldk'))

const filter1 = _.curry(function(fn, array){

? ? return array.filter(fn)

})

console.log(filter1(['ldkk llll', 'liuchao'], haveSpace))

const findSpace = filter1(haveSpace)

console.log(findSpace(['ldkk llll', 'liuchao']))

3. 柯里化實(shí)現(xiàn)原理 模擬實(shí)現(xiàn)lodash.curry方法

function curry(fn){

? ? return function curriedFn(...args){

? ? ? //判斷實(shí)參和行參的個(gè)數(shù)

? ? ? if(args.length < fn.length){

? ? ? ? ? return function(){

? ? ? ? ? ? //? ? return curriedFn(...args.concat([...arguments]))

? ? ? ? ? ? ? return curriedFn(...args.concat(Array.from(arguments)))

? ? ? ? ? }

? ? ? }

? ? ? return fn(...args)

? ? }

}

let curried1 = curry(getSum)

console.log(curried1(1, 2, 3))

console.log(curried1(1)(2)(3))

console.log(curried1(1)(2, 3))

console.log(curried1(1, 2)(3))

4. 函數(shù)柯里化總結(jié)

? ? 1. 柯里化可以讓我們給一個(gè)函數(shù)傳遞較少的參數(shù)得到一個(gè)已經(jīng)記住了某些固定參數(shù)的新函數(shù)

? ? 2. 這是一種對(duì)函數(shù)參數(shù)的‘緩存’

? ? 3. 讓函數(shù)更靈活, 粒度變得更小

? ? 4. 可以把多元函數(shù)轉(zhuǎn)換成一元函數(shù), 可以組合使用函數(shù)產(chǎn)生強(qiáng)大的功能

#### 管道 (自我理解: gulp鏈?zhǔn)綄?shí)現(xiàn))

函數(shù)就是數(shù)據(jù)的管道, 函數(shù)組合就是把這些管道連接起來, 然數(shù)據(jù)穿過多個(gè)管道形成最終結(jié)果

#### 函數(shù)的組合 Compose

1. 純函數(shù)和柯里化很容易寫出洋蔥代碼(f(g(k(x))))

function compose(f, g){

? ? return function(value){

? ? ? ? return f(g(value))

? ? }

}

function reverse (array){

? ? return array.reverse()

}

function first (array){

? ? return array[0]

}

const last = compose(first, reverse)

console.log(last([1, 3, 5, 2]))

2. 函數(shù)組合可以讓我們把細(xì)粒度的函數(shù)重新組合生成一個(gè)新函數(shù)

函數(shù)組合(compose): 如果一個(gè)函數(shù)需要經(jīng)多多個(gè)函數(shù)處理才能得到最終值,這個(gè)時(shí)候可以把中間過程的函數(shù)合并成一個(gè)函數(shù)

**函數(shù)組合默認(rèn)是從右到左執(zhí)行

**函數(shù)組合可以讓代碼最大程度的復(fù)用

// 組合函數(shù)如何調(diào)試

// 實(shí)現(xiàn): NEVER SAY DIE -> never-say-die

const split = _.curry((sep, str) => _.split(str, sep))

const join = _.curry((sep, array) => _.join(array, sep))

const log = v => {

? ? console.log(v)

? ? return v

}

const trace = _.curry((tag, v) => {

? ? console.log(tag, v)

? ? return v

})

const map = _.curry((fn, array) => _.map(array, fn))

// const f = _.flowRight(join('-'), log, map(_.toLower), log, split(' '))

const f = _.flowRight(join('-'), trace('map 后'), map(_.toLower), trace('map 前'), split(' '))

console.log(f('NEVER SAY DIE'))

3. lodash中的組合函數(shù)

// lodash中的組合函數(shù) flow (從左向右執(zhí)行) flowRight (從右向左執(zhí)行)

const reverse = arr => arr.reverse()

const first = arr => arr[0]

const toUpper = s => s.toUpperCase()

const f = _.flowRight(toUpper, first, reverse)

const f = compose(toUpper, first, reverse)

console.log(f(['aldj', 'kdkdkd']))

// 組合函數(shù)的實(shí)現(xiàn)原理 模擬lodash.flowRight

function compose (...args){

? ? return function(value){

? ? ? ? return args.reverse().reduce((acc, fn) => {

? ? ? ? ? ? return fn(acc)

? ? ? ? }, value)

? ? }

}

// 箭頭函數(shù)實(shí)現(xiàn)

const compose = (...args) => value => args.reverse().reduce((acc, fn) => fn(acc), value)

const f = compose(toUpper, first, reverse)

console.log(f(['aldj', 'kdkdkd']))

4. 組合函數(shù)的實(shí)現(xiàn)原理

結(jié)合律(函數(shù)組合要滿足的特點(diǎn))------我們可以把g和h組合, 還可以把f和g組合, 結(jié)果都是一樣的

const h = _.flowRight(_.toUpper, _.first, _.reverse)

const g = _.flowRight(_.toUpper, _.flowRight(_.first, _.reverse))

const h = _.flowRight(_.flowRight(_.toUpper, _.first), _.reverse)

console.log(h(['aldj', 'kdkdkd']))

console.log(g(['aldj', 'kdkdkd']))

5. lodash中的FP模塊

(1)lodash中的FP模塊提供了實(shí)用的函數(shù)式編程友好的方法

(2)提供了不可變的auto-curried iteratee-first data-last 的方法( 將函數(shù)柯里化 方法前置 數(shù)據(jù)后置)

const fp_f = _fp.flowRight(_fp.join('-'), _fp.map(_fp.toLower), _fp.split(' '))

console.log(fp_f('NEVER SAY DIE'))

//lodash中的FP模塊? 和非FP模塊 map方法的區(qū)別

console.log(_.map(['23', '3', '10'], parseInt))

parseInt('23', 0, array)

parseInt('8', 1, array)

parseInt('10', 2, array)

console.log(_fp.map(parseInt, ['23', '3', '10']))

#### PrintFree 編程風(fēng)格

? ? -- 我們可以把數(shù)據(jù)處理的過程定義成與數(shù)據(jù)無關(guān)的合成運(yùn)算,不需要用到代表數(shù)據(jù)的那個(gè)參數(shù), 只要把簡(jiǎn)單的元素按步驟合成到一起, 在使用這種模式之前我們需要定義一些輔助的基本運(yùn)算函數(shù)

? ? ? ? ** 不需要知名處理的數(shù)據(jù)

? ? ? ? ** 只需要合成運(yùn)算過程

? ? ? ? ** 需要定義一些輔助的基本運(yùn)算函數(shù)

// PrintFree 模式

// Hello? ? World -> hello_world

const f = _fp.flowRight(_fp.replace(/\s+/g, '_'), _fp.toLower)

console.log(f('Hello? ? World'))

// PrintFree 案例

// world wild web -> W. W. W.

const firstLetterToUpper = _fp.flowRight(_fp.join('. '), _fp.map(_fp.first), _fp.map(_fp.toUpper), _fp.split(' '))

const firstLetterToUpper = _fp.flowRight(_fp.join('. '), _fp.map(_fp.flowRight(_fp.first, _fp.toUpper)), _fp.split(' '))

console.log(firstLetterToUpper('world wild web'))

#### 函子

#### Functor

1. 容器: 包含值和值的變形(這個(gè)變形關(guān)系就是函數(shù))

2. 函子: 是一個(gè)特殊的容器, 通過一個(gè)普通的對(duì)象來實(shí)現(xiàn), 該對(duì)象具有map方法, map方法可以運(yùn)行一個(gè)函數(shù)對(duì)值進(jìn)行處理(變形關(guān)系)

3. 總結(jié): 1. 函數(shù)式編程的運(yùn)算不直接操作值, 而是由函子完成,

? ? ? ? 2. 函子就是一個(gè)實(shí)現(xiàn)了map契約的對(duì)象

? ? ? ? 3. 我們可以把函子想像成一個(gè)盒子, 這個(gè)盒子里封裝了一個(gè)值

? ? ? ? 4. 行要處理盒子中的值, 我們需要給盒子的方法傳遞藝哥處理值的函數(shù)(純函數(shù)), 有這個(gè)函數(shù)來對(duì)值進(jìn)行處理

? ? ? ? 5. 最終map方法返回一個(gè)包含新值的盒子(函子)

4. 問題: null undefined問題

class Container {

? ? constructor (value){

? ? ? ? this._value = value

? ? }

? ? map(fn){

? ? ? ? return new Container(fn(this._value))

? ? }

}

let r = new Container(5).map(x => x + 1).map(x => x * x)

console.log(r)

class Container {

? ? static of (value){

? ? ? ? return new Container(value)

? ? }

? ? constructor (value){

? ? ? ? this._value = value

? ? }

? ? map(fn){

? ? ? ? return new Container(fn(this._value))

? ? }

}

let r = Container.of(5).map(x => x + 1).map(x => x * x)

console.log(r)

// 問題 (傳入值是null undefined)

Container.of(null).map(x => x.toUpperCase())

#### MayBe函子

? ? MayBe函子的作用就是可以對(duì)外部的空值情況做處理(空值副作用在允許的范圍)

? ? 問題: 多次調(diào)用 不知道哪次調(diào)用出現(xiàn)開始出現(xiàn)null

class MayBe {

? ? static of(value){

? ? ? ? return new MayBe(value)

? ? }

? ? constructor(value){

? ? ? ? this._value = value

? ? }

? ? map(fn){

? ? ? ? return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))

? ? }

? ? isNothing(){

? ? ? ? return this._value === null || this._value === undefined

? ? }

}

let r = MayBe.of('Hello kitty').map(x => x.toUpperCase())

console.log(r)

let r = MayBe.of(null).map(x => x.toUpperCase())

console.log(r)

let r = MayBe.of(null).map(x => x.toUpperCase()).map(x => null).map(x => x.split(' '))

console.log(r)

#### Either函子

? ? Either兩者中的任何一個(gè), 類似于if else 的處理

? ? 異常會(huì)讓函數(shù)變的不純, Either函子可以用來做異常處理

class Left {

? ? static of(value){

? ? ? ? return new Left(value)

? ? }

? ? constructor(value){

? ? ? ? this._value = value

? ? }

? ? map(fn){

? ? ? ? return this

? ? }

}

class Right {

? ? static of(value){

? ? ? ? return new Right(value)

? ? }

? ? constructor(value){

? ? ? ? this._value = value

? ? }

? ? map(fn){

? ? ? ? return Right.of(fn(this._value))

? ? }

}

let r1 = Right.of(12).map(x => x + 2)

let r2 = Left.of(12).map(x => x + 2)

console.log(r1)

console.log(r2)

function parseJSON (str) {

? ? try{

? ? ? ? return Right.of(JSON.parse(str))

? ? } catch(e){

? ? ? ? return Left.of({error: e.message})

? ? }

}

let r = parseJSON('{name: zs}')

console.log(r)

let r = parseJSON('{"name": "zs"}').map(x => x.name.toUpperCase())

console.log(r)

#### IO函子

? ? IO函子的_value是一個(gè)函數(shù),這里是把函數(shù)作為值來處理

? ? IO函子可以把不純的動(dòng)作存儲(chǔ)到_value中, 延遲執(zhí)行這個(gè)不純的操作(惰性執(zhí)行), 包裝但前的操作純

? ? 把不純的操作交給調(diào)用者來處理

? ? 作用: 把傳入函子的不純操作延后, 交給調(diào)用者執(zhí)行, 不再函子中執(zhí)行, 保證函子的純

class IO {

? ? static of(value){

? ? ? ? return new IO(function(){

? ? ? ? ? ? return value

? ? ? ? })

? ? }

? ? constructor(fn){

? ? ? ? this._value = fn

? ? }

? ? map(fn){

? ? ? ? return new IO(_fp.flowRight(fn, this._value))

? ? }

}

let r = IO.of(process).map(v => v.execPath)

console.log(r)

console.log(r._value())

#### IO函子的問題? 多次調(diào)用_value才能拿到目標(biāo)數(shù)據(jù)

// IO函子的問題

let readFile = function(filename){

? ? return new IO(function(){

? ? ? ? return fs.readFileSync(filename, 'utf-8')

? ? })

}

let print = function(x){

? ? return new IO(function(){

? ? ? ? console.log(x)

? ? ? ? return x

? ? })

}

// let cat = _fp.flowRight(print, readFile)

//IO(IO(x))

// let r = cat('package.json')

// console.log(r)

// let r = cat('package.json')._value()._value()

// console.log(r)

let r = readFile('package.json')

// .map(x => x.toUpperCase())

.map(_fp.toUpper)

.flatMap(print).join()

console.log(r)

#### Monad函子

? ? Monad函子是可以變扁的函子 IO(IO(x))

? ? 一個(gè)函子如果具有join和of兩個(gè)方法并遵守一些定律就是一個(gè)Monad

class IO {

? ? static of(value){

? ? ? ? return new IO(function(){

? ? ? ? ? ? return value

? ? ? ? })

? ? }

? ? constructor(fn){

? ? ? ? this._value = fn

? ? }

? ? map(fn){

? ? ? ? return new IO(_fp.flowRight(fn, this._value))

? ? }

? ? join(){

? ? ? ? return this._value()

? ? }

? ? flatMap(fn){

? ? ? ? return this.map(fn).join()

? ? }

}

#### Pointed函子

? ? Pointed孩子是實(shí)現(xiàn)的of靜態(tài)方法的函子

? ? of方法是為了避免使用new來創(chuàng)建對(duì)象, 更深層的含義是of方法用來把值放到上下文Context(把值放到容器中, 使用map來處理)

#### folktale 不用于lodash ramda的庫, 只提供了一些函數(shù)式操作, 例如: compose、curry等 一些Task、Either、MayBe函子

? ? Task異步執(zhí)行

// folktale庫(2.3.2)

const { compose, curry } = require('folktale/core/lambda')

// let f = curry(2, (x, y) => {

//? ? return x + y

// })

// console.log(f(1, 3))

// console.log(f(1)(3))

// let f = compose(_fp.toUpper, _fp.first)

// console.log(f(['one', 'tow']))

// Task函子 處理異步任務(wù)

// const { task } = require('folktale/concurrency/task')

// function readFile (filename){

//? ? return task( resolver => {

//? ? ? ? fs.readFile(filename, 'utf-8', (err, data) => {

//? ? ? ? ? ? if(err) resolver.reject(err)

//? ? ? ? ? ? resolver.resolve(data)

//? ? ? ? })

//? ? })

// }

// let r = readFile('package.json').map(_fp.split('\n')).map(_fp.find(x => x.includes('version'))).run().listen({

//? ? onRejected: err => {

//? ? ? ? console.log(err)

//? ? },

//? ? onResolved: value => {

//? ? ? ? console.log(value)

//? ? }

// })

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容