# fed-e-task-01-01 **Repository Path**: learning-summary/fed-e-task-01-01 ## Basic Information - **Project Name**: fed-e-task-01-01 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-25 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 模块一:函数式编程与 JS 异步编程、手写 Promise参考答案 #### 简答题 ### 一、谈谈你是如何理解 JS 异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务?**** > **JS异步编程**: javascript是单线程的,执行顺序是从上至下,但是会遇到异步任务,相当于放到了浏览器中的异步调用栈,这样就不会对js执行栈造成阻塞。 > > **EventLoop**: 在浏览器中有两个栈,一个是js执行栈(执行同步代码),一个是异步调用栈(放入异步)。js执行过程中,遇到同步代码,js执行栈会立即调用,当遇到异步代码,先放入异步调用栈中,根据宏任务还是微任务放到宏任务、微任务队列中,当所有的同步代码执行完了以后,先执行微任务队列的微任务,然后再执行宏任务队列中的任务。**** > > **消息队列**:存放异步任务,并把异步任务推入执行栈。**** > > **宏任务:** 主要是setTimout, setInterval > > **微任务:** 主要是promise.then, process.nextTick ------ #### 代码题 ### 一、将下面异步代码使用 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); ``` > 参考代码: > > ```js > let promiseA = Promise.resolve('hello') > let promiseB = Promise.resolve('lagou') > let promiseC = Promise.resolve('I ❤️ U') > > Promise.all([promiseA, promiseB, promiseC]).then(result => { > console.log(result.join(' ')) > }) > ``` ------ ### 二、基于以下代码完成下面的四个练习 ```js const fp = require('lodash/fp') // 数据:horsepower 马力,dollar_value 价格,in_stock 库存 const cars = [ { name: 'Ferrari FF', horsepower: 660, dollar_value: 700000, in_stock: true }, { name: 'Spyker C12 Zagato', horsepower: 650, dollar_value: 648000, in_stock: false }, { name: 'Jaguar XKR-S', horsepower: 550, dollar_value: 132000, in_stock: false }, { name: 'Audi R8', horsepower: 525, dollar_value: 114200, in_stock: false }, { name: 'Aston Martin One-77', horsepower: 750, dollar_value: 185000, in_stock: true }, { name: 'Pagani Huayra', horsepower: 700, dollar_value: 130000, in_stock: false } ] ``` #### 练习1:使用组合函数 fp.flowRight() 重新实现下面这个函数 ```js let isLastInStock = function(cars){ // 获取最后一条数据 let last_car = fp.last(cars) // 获取最后一条数据的 in_stock 属性值 return fp.prop('in_stock', last_car) } ``` > 先定义获取最后一条数据的函数,再定义获取某个对象中的 in_stock 属性的函数,再用 fp.flowRight 组合函数 ```js let f = fp.flowRight(fp.prop('in_stock'), fp.last) console.log(f(cars)) ``` #### 练习2:使用 fp.flowRight()、fp.prop() 和 fp.first() 获取第一个 car 的 name > 先定义获取第一条数据的函数,再定义获取某个对象中的 name 属性的函数,再用 fp.flowRight 组合函数 ```js let f = fp.flowRight(fp.prop('name'), fp.first) console.log(f(cars)))) ``` #### 练习3:使用帮助函数 _average 重构 averageDollarValue,使用函数组合的方式实现 ```js let _average = function(xs){ return fp.reduce(fp.add, 0, xs) / xs.length } ``` > 先定义获取某个对象中的 dollar_value 属性的函数,将该函数作为 fp.map 的数组元素处理函数,再用 fp.flowRight 组合函数 ```js let averrageDollarValue = fp.flowRight(_average ,fp.map(car => car.dollar_value)) console.log(averrageDollarValue(cars)) ``` #### 练习4:使用 flowRight 写一个 sanitizeNames() 函数,返回一个下划线连续的小写字符串,把数组中的 name 转换为这种形式,例如:sanitizeNames(["Hello World"]) => ["hello_world"] ```js let _underscore = fp.replace(/\W+/g, '_') // 无须改动,并在 sanitizeNames 中使用它 ``` > 先定义获取某个对象中的 name 属性的函数,再定义转化为小写的函数,再将空格和下划线替换,,再用 fp.flowRight 组合函数 ```js let _underscore = fp.replace(/\W+/g, '_') let f = fp.flowRight(_underscore, log('map之后'),fp.map(car => car.name)) console.log(f(cars)) ``` ------ ### 三、基于下面提供的代码,完成后续的四个练习 ```js // 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 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(f,x) 创建一个能让 functor 里的值增加的函数 ex1 ```js const fp = require('lodash/fp') const {Maybe, Container} = require('./support') let maybe = Maybe.of([5,6,1]) let ex1 = () => { // 你需要实现的函数。。。 } ``` > 函子对象的 map 方法可以运行一个函数对值进行处理,函数的参数为传入 of 方法的参数;接着对传入的整个数组进行遍历,并对每一项执行 fp.add 方法 ```js let maybe = Maybe.of([5,6,1]) let ex1 = () => { // 你需要实现的函数。。。 return maybe.map((x) => { return fp.reduce((total, item) => { return total + item }, 0 ,x) })._value } console.log(ex1()) ``` #### 练习2:实现一个函数 ex2,能够使用 fp.first 获取列表的第一个元素 ```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 = () => { // 你需要实现的函数。。。 } ``` > 解答如下: ```js let ex2 = (xs) => { return xs.map(fp.first)._value } console.log(ex2(xs)) ``` #### 练习3:实现一个函数 ex3,使用 safeProp 和 fp.first 找到 user 的名字的首字母 ```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 = () => { // 你需要实现的函数。。。 } ``` > 调用 ex3 函数传入 user 对象,safeProp 是经过柯里化处理的,可以先传“属性”参数,后传“对象”参数。safeProp 函数处理后返回 user 的值,再调用fp.first 获取首字母 ```js let ex3 = () => { return safeProp('name')(user).map(fp.first)._value } console.log(ex3()) ``` #### 练习4:使用 Maybe 重写 ex4,不要有 if 语句 ```js const fp = require('lodash/fp') const {Maybe, Container} = require('./support') let ex4 = function(n){ if(n){ return parseInt(n) } } ``` > MayBe 函子用来处理外部的空值情况,防止空值的异常,拿到函子的值之后进行 parseInt 转化 ```js let ex4 = function(n){ return Maybe.of(n).map(parseInt)._value } ``` ------ ### 四、手写实现 MyPromise 源码 要求:尽可能还原 Promise 中的每一个 API,并通过注释的方式描述思路和原理。【参考代码】 ```js ```