函数式概念test1.2

这篇博客探讨了函数式编程的概念,特别是通过模拟Promise来理解其工作原理。内容包括使用setTimeout改写Promise,利用lodash的函数组合实现特定功能,如获取数组中第一个对象的属性,以及重构和优化函数。此外,文章还提供了几个基于fp.add、fp.map等函数的练习,旨在增强读者对函数式编程技巧的掌握。最后,作者手写了Promise的源码,并详细解释了Promise的基础调用、链式调用、错误处理和并发控制。
摘要由CSDN通过智能技术生成

函数式概念test1.2

Promise 模拟

一 、setTimeout 改写promise


setTimeout(function() {
    var a = 'hello'
    setTimeout(() => {
        var b = 'lagou'
        setTimeout(() => {
            var c = 'I ❤ U'
                // console.log(a + b + c);
        }, 10);
    }, 10);
}, 10)


let pro = new Promise((resolve, reject) => {
    resolve('hello')
})

方案一:
pro.then(value => {
    // console.log(value);
    return value
}).then(value => {
    // console.log(value)
    return value + 'logou'
}).then(value => {
    // console.log(value);
    return value + 'I ❤ U'
}).then(value => {
     console.log(value);

方案二:
function a() {
    return new Promise((resolve, reject) => {
        resolve('hello')
    })
}

function b(data) {
    return new Promise((resolve, reject) => {
        resolve(data + 'lagou')
    })
}

function c(data) {
    return new Promise((resolve, reject) => {
        resolve(data + 'I ❤ U')
    })
}

a().then(value => { return b(value) })
    .then(value => { return c(value) })
    .then(value => { console.log(value); })

二 、基于lodash的联系

const fp = require('lodash/fp')
// 数据
// horsepower 马力,doller_value 价格, in_stock 库存

const cars = [{
    name: 'Ferrari FF',
    horsepower: 660,
    doller_value: 700000,
    in_stock: true
}, {
    name: 'Spyker C12 Zagato',
    horsepower: 650,
    doller_value: 648000,
    in_stock: false
}, {
    name: 'Jaguar XKR-S',
    horsepower: 550,
    doller_value: 132000,
    in_stock: false
}, {
    name: 'Audi R8',
    horsepower: 525,
    doller_value: 114200,
    in_stock: false
}, {
    name: 'Aston Martin One-77',
    horsepower: 750,
    doller_value: 1850000,
    in_stock: true
}, {
    name: 'Pagani Huayra',
    horsepower: 700,
    doller_value: 1300000,
    in_stock: false
}]
  1. 使用函数组合fp.flowRight()实现以下函数:
let isLastInStock = function(cars) {
    // 获取最后一条数据
    let last_car = fp.last(cars)
        // 获取最后一条数据的in_stock属性值
    return fp.prop('in_stock', last_car)
}

console.log(isLastInStock(cars)); //false

let isLastInStockEl = fp.flowRight(fp.prop('in_stock'), fp.last)
console.log(isLastInStockEl(cars));  //false

  1. 使用fp.flowRight()、 fp.prop() 和fp.first() 获取第一个car的name:
let carsFirstName = fp.flowRight(fp.prop('name'), fp.first)
console.log(carsFirstName(cars));  //Ferrari FF
  1. 使用帮助函数_average 重构averageDollarValue,使用函数组合的方式实现
let _average = function(xs) {
        return fp.reduce(fp.add, 0, xs) / xs.length
    } //不改动

let averageDollarValue = function(cars) {
    let doller_values = fp.map(function(car) {
        return car.doller_value
    }, cars)
    return _average(doller_values)
}

console.log(averageDollarValue(cars));  //790700

let averageDollarValueEl = fp.map(item => item.doller_value)
let combinationFn = fp.flowRight(_average, averageDollarValueEl)
console.log(combinationFn(cars))  //790700
  1. 使用flowRight()写一个sanitizeNames()函数,返回一个下划线连接的小写字符串, 把数组中的name转换为这种形式:例如:sanitizeNames([“Hello World”])=>[“hello_world”]
let _underscore = fp.replace(/\W+/g, '_') //无需改动,并在sanitizeNames中使用它

let sanitizeNames = fp.flowRight(_underscore, fp.lowerCase, fp.startCase)
console.log(sanitizeNames(['Hello World']));  //hello_world

三 、 基于下面提供的代码,完成后续四个练习

supports.js 为class封装类,已提供

 // supports.js 

 class Container {
     static of(value) {
         return new Container(value)
     }
     constructor(value) {
         this._value = value
     }
     map(fn) {
         return Container.of(fn(this._value))
     }
 }
 class Maybe {
     static of(x) {
         return new Maybe(x)
     }
     isNothing() {
         return this._value === null || this._value === undefined
     }
     constructor(x) {
         this._value = x
     }
     map(fn) {
         return this.isNothing() ? this : Maybe.of(fn(this._value))
     }
 }

 module.exports = { Maybe, Container }
  1. 使用fp.add(x,y)和fp.map()创建一个能让functor里的值增加的函数ex1
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')

let maybe = Maybe.of([5, 6, 1])
    // let container = Container.of([5, 6, 1])

let ex1 = () => {
    // 你需要实现的函数
    return maybe.map(x => {
        return fp.map(fp.add(2), x)
    })
}
console.log("ex1", ex1());  //ex1 Maybe { _value: [ 7, 8, 3 ] }
console.log("maybe", maybe);  //maybe Maybe { _value: [ 5, 6, 1 ] }
  1. 实现一个函数ex2,能够使用fp.first获取列表的第一个元素
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])

let ex2 = () => {
       // 需要实现
       return xs.map(x => {
           return fp.first(x)
       })._value
   }
let ex2 = () => xs.map(fp.first)._value
console.log("ex2", ex2());  //ex2 do

  1. 实现一个函数ex3,使用safeProp 和fp.first找到user的名字的首字母
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let safeProp = fp.curry(function(x, o) {
   return Maybe.of(o[x])
})
let user = { id: 2, name: 'Albert' }
let ex3 = function(user) {
   return safeProp('name', user).map(x => {
       return fp.first(x)
   })._value
}

console.log(ex3(user));   //A
  1. 使用Maybe 重写ex4, 不要有if 语句
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
   let ex4 = function(n) {
       if (n) {
           return parseInt(n)
       }
   }
let ex4 = (e) => {
   return Maybe.of(parseInt(e))._value
}


console.log(ex4("5"));   //5

四 、手写promsie源码(尽量还原promise的api),注释的方式描述思路和原理

MyPromise.js 为封装promise

// Promise  模擬
// 执行状态
const PENDDING = 'pendding' //等待
const FUILEED = 'fuilleed' //成功
const REJECT = 'reject' //失败

class MyPromise {
    status = PENDDING //对象内的状态初始化
    value = undefined //回调成功初始值
    reason = undefined //回调失败初始值
    successCallback = [] //成功的回调
    failCallback = [] //失败的回调
    constructor(excutor) { //内置生成器,生成一个处理成功和失败的调用函数(resolve,reject)
        try { //执行器错误捕获
            excutor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    resolve = value => { //成功的值
        if (this.status !== PENDDING) { //判断执行状态是否是等待状态,等待则登出
            return
        }
        this.status = FUILEED //状态赋值,状态一旦确定不可更改
        this.value = value //回调参数赋值
        while (this.successCallback.length) {
            this.successCallback.shift()()
        }
        // this.successCallback && this.successCallback(this.value) //回调函数传参
    }
    reject = reason => { //失败的值(原因)
        if (this.status !== PENDDING) {
            return
        }
        this.status = REJECT
        this.reason = reason
        while (this.failCallback.length) {
            this.failCallback.shift()()
        }
        // this.failCallback && this.failCallback(this.reason)
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        } else {
            return new MyPromise(resolve => resolve(value))
        }
    }
    static all(arr) { //all()处理异步并发,限定执行顺序对应执行结果
        // 获取传入数组,定义结果容器,定义异步等待下标
        let result = []
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function saveArr(key, value) {
                result[key] = value //存入执行结果于数组容器
                index++ //所有的遍历记录
                if (index == arr.length) { //当记录值与数组下标相等,表示遍历完毕数组所有值 
                    resolve(result) //回调这个返回数组结果的容器
                }
            }
            for (let i = 0; i < arr.length; i++) {
                // 遍历传参数组,判断每个当前值是否是promise对象
                // 如果是则当前值的回调函数结果存入数组容器(成功返回值,失败返回原因),
                // 如果不是当前值存入数组容器
                if (arr[i] instanceof MyPromise) {
                    arr[i].then(value => saveArr(i, value), reason => reject(reason))
                } else {
                    saveArr(i, arr[i])
                }
            }
        })
    }

    finally(callback) {
        // this.then:获取当前的promise执行状态
        return this.then(value => {
            // callback返回的值通过resolve转换为promise
            return MyPromise.resolve(callback()).then(() => value)
                // callback()
                //     // 下一个then,传参
                // return value
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
                // callback()
                // return reason
        })
    }
    then(successCallback, failCallback) { //成功或者失败的回调处理
        // 判断thens是否参数可选:没有则返回这个函数,有则返回这个值
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason }
            // 生成一个promsie对象,返回输出结果,可以访问对象的属性及方法
        let promiseEl = new MyPromise((resolve, reject) => {
            // 状态判断,差异化返还执行结果
            if (this.status == FUILEED) {
                setTimeout(() => {
                    try { //then回调错误捕获
                        // successCallback(this.value)获取第一次返回值
                        // resolve(resetValue):重新把return的值交给resolve处理
                        // 用于链式调用,return新值
                        // 由于此事件会在成功/失败/等待都会执行,因此封装
                        let resetValue = successCallback(this.value)
                            // console.log("reset", resetValue);   //reset 100
                            // resolve(resetValue)
                        resolvePromise(promiseEl, resetValue, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }

                }, 0);
            } else if (this.status == REJECT) {
                setTimeout(() => {
                    try {
                        let resetValue = failCallback(this.reason)
                        resolvePromise(promiseEl, resetValue, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            } else {
                //异步处理:当入参是一个异步值时,需要临时将其存入返还
                // 等待这两个函数被调用,执行resolve或者reject的successCallback&failCallback
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try { //then回调错误捕获
                            // successCallback(this.value)获取第一次返回值
                            // resolve(resetValue):重新把return的值交给resolve处理
                            // 用于链式调用,return新值
                            // 由于此事件会在成功/失败/等待都会执行,因此封装
                            let resetValue = successCallback(this.value)
                                // console.log("reset", resetValue);   //reset 100
                                // resolve(resetValue)
                            resolvePromise(promiseEl, resetValue, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }

                    }, 0);
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let resetValue = failCallback(this.reason)
                            resolvePromise(promiseEl, resetValue, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0);
                })
            }
        })
        return promiseEl
    }
    catchEl(failCallback) {
        // 传参为回调函数,通过then的两个处理方式(成功,失败),注册失败函数
        return this.then(undefined, failCallback)
    }


}

function resolvePromise(promiseEl, resetValue, resolve, reject) {
    if (promiseEl === resetValue) { //捕获自己调用自己的情况
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (resetValue instanceof MyPromise) {
        // resetValue.then(value => resolve(value), reason => reject(reason))
        resetValue.then(resolve, reject)
    } else {
        resolve(resetValue)
    }
}

module.exports = MyPromise
  1. Promise 基础调用、多次调用
const MyPromise = require('./promise_simulate')

let pro = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
    resolve('Promise doing...')
        // }, 2000);
})

// 多次调用
let pro = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
    resolve('Promise doing...')
        // }, 2000);
})

多次调用
pro.then(value => {
    console.log('fulled', value);
}, reason => {
    console.log('rejected', reason);
})
pro.then(value => {
    console.log('fulled1', value);
}, reason => {
    console.log('rejected1', reason);
})
pro.then(value => {
    console.log('fulled2', value);
}, reason => {
    console.log('rejected2', reason);
})
  1. 链式调用
// 链式调用

// 新建一个返回的promise
let pro = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
    resolve('Promise doing...')
        // }, 2000);
})
const resetPro = new MyPromise((resolve, reject) => {
    resolve('resetPro')
})


pro.then(value => {
    console.log(value);
    return resetPro;
}).then(value => {
    console.log(value);
})

  1. 捕获报错
let pro = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
    // throw new Error('excutor error')
    resolve('Promise doing...')
        // }, 2000);
})

let p1 = pro.then(value => {
    console.log(value);
    // throw new Error('then error ')
     return p1;
}, reason => {
    console.log(reason);
})
p1.then(value => {
    console.log(value);
}, reason => {
    console.log('next then error', reason);
})
  1. 错误情况及捕获返回值
// 错误情况捕获返回值
let pro = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        // throw new Error('excutor error')
        resolve('Promise doing...')
            // reject('Promise Fail...')
    }, 2000);
})
pro.then(value => {
    console.log(value);
    return 'sss'
}, reason => {
    console.log(reason);
    return 1111
}).then(value => {
    console.log(value);
})

  1. then 参数可选:没有,返回函数处理,有则返回 这个值
let pro = new MyPromise((resolve, reject) => {
    resolve('Promise doing...')
})

pro.then().then().then(value => console.log(value))

  1. Promise.all() 处理异步并发解决:异步调用顺序返回异步结果(对应关系,无关异步)
let pro = new MyPromise((resolve, reject) => {
    resolve('Promise doing...')
})

function pro1() {
    return new MyPromise((resolve, reject) => {
        resolve(100)
    })
}

function pro2() {
    return new MyPromise((resolve, reject) => {
        resolve('work1')
    })
}


MyPromise.all(['a', 'b', 'c', pro1(), pro2(), 'd']).then(values => console.log(values))


  1. promise.resolve():返回一个传入值,进行返回

如果是promise对象,则返回该值;如果不是对象,则返回该promise的resolve的调用

let pro = new MyPromise((resolve, reject) => {
    resolve('Promise doing...')
})

function pro1() {
    return new MyPromise((resolve, reject) => {
        resolve(22)
    })
}

MyPromise.resolve(100).then(value => console.log(value))
MyPromise.resolve(pro1()).then(value => console.log(value))
  1. promise.finally() prmoise是否成功都会调用的一个额外操作
let pro = new MyPromise((resolve, reject) => {
    resolve('Promise doing...')
        // reject('Promise failing...')
})

function pro1() {
    return new MyPromise((resolve, reject) => {
        // resolve(100)
        setTimeout(() => {
            reject(222)
        }, 2000);
    })
}

pro1().finally(() => {
    console.log("finally");
    return pro1()
}).then(value => {
    console.log(value);
})

  1. Promise.catch():用来处理报错信息
function pro1() {
    return new MyPromise((resolve, reject) => {
        // resolve(100)
        reject('fail')
    })
}

pro1()
    .then(value => console.log(value))
    .catchEl(reason => console.log(reason))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值