# fed-e-task-01-01 **Repository Path**: zhuyong2/fed-e-task-01-01 ## Basic Information - **Project Name**: fed-e-task-01-01 - **Description**: No description available - **Primary Language**: JavaScript - **License**: MulanPSL-1.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-03-22 - **Last Updated**: 2021-07-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # fed-e-task-01-01 #### code 为代码目录 #### notes 为笔记目录 ## 函数式编程与js异步编程、手写promise --- ### 简答题 #### 一、谈谈你是如何理解js异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务 ``` js是单线程语言,为了避免dom渲染冲突,所以就有了同步模式和异步模式 异步模式呢就是不需要等待上一个任务结束再开始执行。 举例 排队 我前面有个人在处理事务 但是我可以不用等他处理完 我就可以处理我的事务 EventLoop(事件循环) 决定了什么时候执行同步什么时候执行异步 步骤: 同步模式代码放在执行栈里 立即执行 异步代码放在消息队列里(异步任务队列) 暂时不执行 同步代码执行完后再执行异步任务里的代码 然后异步代码里的 又分 宏任务 和 微任务 微任务在消息队列里执行优先级更高 常见有 parmise.then 宏任务在消息队列里执行优先级较低 常见有 setTimeout setInterval requestAnimationFarme 在 执行栈里 没有代码执行后 EventLoop 会去 消息队列里 如果有微任务 就调用微任务到执行栈里 然后调用宏任务到执行栈里 ``` ### 代码题 #### 一、将下列异步代码使用promise 的方法改进 ``` setTimeout(function () { var a = 'hello' setTimeout(function () { var b = 'lagou' setTimeout(function () { var c = 'I ❤ U' console.log(a + b +c) }, 10) }, 10) }, 10) ``` ``` function timeout(s) { let num = s return (str) => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(str) }, num) }) } } let a = timeout(10) a('hello').then(res => { return a(res + 'lagou') }).then(res => { return a(res + 'I ❤ U') }).then(res => { console.log(res) }) ``` #### 二、基于以下代码完成下面的四个练习 ``` const fp = require('lodash/fp'); // 数据 // hp 马力 dv 价格 is 库存 const cars = [ { name: 'ferrari ff', hp: 660, dv: 700000, is: true}, { name: 'Spyker C12', hp: 650, dv: 648000, is: false}, { name: 'Jaguar XKR-S', hp: 550, dv: 132000, is: true}, { name: 'Audi R8', hp: 525, dv: 114200, is: false}, { name: 'Aston Martin One-77', hp: 750, dv: 1850000, is: true}, { name: 'paganism Huayra', hp: 770, dv: 1300000, is: false}, ] ``` #### 练习1:使用函数组合 fp.flowRight() 重新实现下面这个函数 ``` let isLastInStock = function (cars) { // 获取最后一条数据 let last_car = fp.last(cars) // 获取最后一条数据的is 属性值 return fp.prop('is', last_car) } ``` ``` fp.flowRight(fp.prop('is'), fp.last) ``` #### 练习2:使用fp.flowright()、fp.prop()和fp.first()获取第一个car的name ``` fp.flowRight(fp.prop('name'), fp.first) ``` #### 练习3:使用帮助函数_average重构averageDollarValue, 使用函数组合的方式实现 ``` let _average = function(xs) { return fp.reduce(fp.add, 0,xs) // xs.length } // <- 无需改动 let averageDollarValue = function (cars) { let dollar_value = fp.map(function (car) { return car.doolar_value }, cars) return _average(dollar_value) } ``` ``` let _average = function(xs) { return fp.reduce(fp.add, 0,xs) // xs.length } // <- 无需改动 let averageDollarValue = function (cars) { return fp.map(function (car) { return car.dv }, cars) } function compose(a, d) { return function (val) { return a(d(val)) } } let s = compose(_average,averageDollarValue) console.log(s(cars)) ``` #### 练习4:使用 flowright写一个 sanitizenames()函数,返回一个下划线连接的小写字符串,把数组中的name转换为这种形式:例如: sanitizeNames(["Hello World"])=>["hello_world"] ``` let _underscore= fp.replace(/\W+/g, '_') //<-无须改动,并在 sanit1zeNames中使用它 ``` ``` let _underscore= fp.replace(/\W+/g, '_') //<-无须改动,并在 sanit1zeNames中使用它 const sanit1zeNames = fp.flowRight(fp.map(_underscore), fp.map(fp.toLower)) console.log(sanit1zeNames(["Hello World", "Hello World"])) // [ 'hello_world', 'hello_world' ] ``` ### 三、基于下面提供的代码、完成后续的四个练习 ``` // support.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 Math(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(f,x) 创建一个能让functor里的值增加的函数 ex1 ``` // app.js const fp = require('lodash/fp') const { Maybe, Container } = require('./support') let maybe = Maybe.of([5, 6, 1]) ``` ``` let ex1 = () => { Maybe.of(maybe._value).map(fp.map(fp.add(1))) // { _value: [ 6, 7, 2 ]} } ``` #### 练习2: 实现一个函数ex2, 能够使用fp.first 获取列表的第一个元素 ``` // app.js const fp = require('lodash/fp') const { Maybe, Container } = require('./support') let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'Do']) let ex2 = () => { // 需要实现的函数 } ``` ``` let ex2 = () => { return Container.of(xs._value).map(fp.first) // {_value: 'do'} } ``` #### 练习3: 实现一个函数ex3, 使用safeProp 和 fp.first 找到user的名字的首字母 ``` // app.js 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 = () => { // 你需要实现的函数 } ``` ``` let ex3 = () => { let a = fp.flowRight(fp.first, safeProp('name')) console.log(a(user)) // A } ``` #### 练习4: 使用Maybe 重写ex4 , 不要有if语句 ``` // app.js const fp = require('lodash/fp') const { Maybe, Container } = require('./support') let ex4 = function (n) { if (n) { return parseInt(n) } } ``` ``` let ex4 = function (n) { return Maybe.of(n).map(parseInt) } ``` ### 四、手写实现 MyPromise 源码 #### 要求:尽可能还原Promise 中的每一个API,并通过注释的方式描述思路和原理。 ``` // myPromise.js // promise 的状态 const PENDING = 'pending' // 等待状态 初始状态 const FULFILLED = 'fulfilled' // 成功状态 const REJECTED = 'rejected' // 失败状态 class MyPromise { status = PENDING // 初始状态 $value = undefined // 成功之后的值 $reason = undefined // 失败之后的值 successCallback = [] // 成功回调函数 failCallback = [] // 失败回调函数 constructor(execoter) { // 错误捕捉 try { execoter(this.resolve, this.reject) } catch (error) { this.reject(error) } } resolve = value => { if(this.status !== PENDING) {return} // 如果状态不是初始状态 等待中 那么不进行操作 this.status = FULFILLED // 状态更改为成功 this.$value = value // 保存成功后的值 while(this.successCallback.length) this.successCallback.shift()() // 如果成功回调存在 那么就进行调用 } reject = reason => { if(this.status !== PENDING) {return} // 如果状态不是初始状态 等待中 那么不进行操作 this.status = REJECTED // 状态更改为失败 this.$reason = reason // 保存失败后的原因 while(this.failCallback.length) this.failCallback.shift()() // 如果失败回调存在 那么就进行调用 } then(successCallback, failCallback) { // 返回 MyPromise successCallback = successCallback ? successCallback : value => value // 判断回调函数是否有参数 如果没有 返回上一个参数 failCallback = failCallback ? failCallback : reason => reason let promise2 = new MyPromise((resolve, reject) => { // 返回一个新的promise if (this.status === FULFILLED) { // 如果状态为失败 common(promise2 ,s, resolve, reject, successCallback, this.$value) } else if (this.status === REJECTED) { // 如果状态为成功 common(promise2 ,s, resolve, reject, failCallback, this.$reason) } else { // 如果是异步函数 将成功回调和失败回调存起来 this.successCallback.push(() => common(promise2 ,s, resolve, reject, successCallback, this.$value)) this.failCallback.push(() => common(promise2 ,s, resolve, reject, failCallback, this.$reason)) } }) return promise2 } finally(callback) { return this.then( val => MyPromise.resolve(callback()).then(() => val), err => MyPromise.resolve(callback()).then(() => { throw err }) ) } catch(failCallback) { return this.then(undefined, failCallback) } static all(array) { let result = [] // 结果 let index = 0 //存储一个数 return new MyPromise((resolve, reject) => { function addData(key, val) { result[key] = val // 储存进对应值 // 这里 创建index 每次addData 后 index ++ index++ if (index === array.length) { // 这里为什么这么做 是因为 如果有异步函数, 那么需要等待异步函数结束后才能 调用成功函数 // 而 forx循环是瞬间执行并不会等待异步函数 而array[i].then是处理了异步函数的 // then异步函数结束后 会调用 reslove 也就是 addData(i, val) // 当 异步函数结束后 addData调用 index++ array内所有执行完后 调用成功函数 resolve(result) } } for (let i = 0; i < array.length; i++) { let current = array[i]; if (current instanceof MyPromise) { // MyPromise 对象 // 这里执行 这个myPromise current.then(val => addData(i, val), reject) // 如果是成功的回调函数 那么就存储进result 如果是失败的回调函数 那么直接 调用返回失败 } else { addData(i, current) // 普通值 添加进结果里 } } }) } static resolve(val) { // 直接返回成功状态 if (val instanceof MyPromise) { // 如果为MyPromise 那么直接返回值 return val } return new MyPromise(resolve => resolve(val)) // 如果为普通值 那么创建一个新的MyPromise 返回 } } function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { // 判断 返回的值是否就是当前值 return reject(new TypeError('chaining cycle detected for promise #')) // 返回类型错误 } if (x instanceof MyPromise) { // 判断是否是 MyPromise 是 就给对应事件传递对应参数 // x.then(value => resolve(value), reason => reject(reason)) x.then(resolve, reject) } else { resolve(x) } } function common(promise2, s, resolve, reject, callback, value) { setTimeout(() => { // 异步 方便获得 promise2 因为是在内部 try { // 错误捕捉 let s = callback(value) resolvePromise(promise2 ,s, resolve, reject) } catch (error) { reject(error) } }, 0) } ```