# fed-e-task-01-01 **Repository Path**: wanghan0321/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-07-21 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 模块一:函数式编程与JS异步编程。手写Promise 作业简答 ## 简答题 谈谈你是如何理解JS异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务? 解: JS最初的设计主要是针对浏览器的Dom做操作的,也就导致了JS的单线程运行机制;由于单线程的运行机制,就意味着没有线程协同处理任务,所以的任务需要排队执行,如果遇到耗时任务,那么就会发生阻塞。 **JS异步编程**的首要任务就是用来提高JS单线程执行机制下的处理效率。有效的防止阻塞的出现。 常用的JS异步编程的处理函数有回调函数、事件、Promise、Generator、Asunc Await **EventLoop、消息队列、宏任务、微任务都是支持JS异步工作的主要内容。** 在JS引擎执行一段代码的过程中,主要会经历几个阶段: 读取代码=> 压入执行栈=> 执行栈处理各个任务=> 遇到同步任务,处理完,排出执行栈,=> 遇到异步任务,执行栈处理完后,会委托宿主环境去执行任务,约定执行后,再将与这个任务的执行结果通过之前约定好的回调函数注册到消息队列=> 当执行栈的任务已经执行完成,空闲时=> 通过EventLoop会监测到,此时便将消息队列中的任务压入执行栈,逐个执行。 **宏任务**是消息队列里的任务,常见的接口请求、定时器等异步任务都是宏任务。 **微任务**是基于当前任务产生而随当前任务结束后立即执行的任务,所以也是异步任务, 但是不需要通过EventLoop监测,通过消息队列取出并压入执行栈中再执行; 像通过Promise产生的任务都为微任务。 ## 代码题(解题思路烦劳老师移步app.js) ### 一、将下面异步代码使用Promise的方法改进 ``` javascript setTimeout(function () { var a = 'hello' setTimeout(function () { var b = 'lagou' setTimeout(function () { var c = 'I ♥ U' console.log('setTimeout',a + b + c) }, 10) }, 10) }, 10) ``` 解: ```javascript const promise = new Promise((resolve, reject) => { setTimeout(() => { var a = 'hello' resolve(a) }, 10) }) promise.then(reverse => { var b = 'lagou' return reverse + b }).then(reverse => { var c = 'I ♥ U' return reverse + c }).then(reverse => console.log('promise',reverse)) ``` ![](E:\webLearn\fed-e-task-01-01\image\01-01.png) ### 二、基于以下代码完成下面的四个练习 ```javascript const fp = require('lodash/fp') //数据 // horsepower 马力,dollar_value 价格,in_stock 库存 const cars = [ { name: 'Ferrari FF', horsepower: 600, 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: 1850000, in_stock: true }, { name: 'Pagani Huayra', horsepower: 700, dollar_value: 1300000, in_stock: false }, ] ``` #### 练习1:使用函数组合fp.flowRight()重新实现下面这个函数 ```javascript let isLastInStock = function (cars) { //获取最后一条数据 let last_car = fp.last(cars) //获取最后一条数据的in_stock属性 return fp.prop('in_stock',last_car) } ``` 解: ```javascript let isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last) ``` ![](E:\webLearn\fed-e-task-01-01\image\02-01.png) #### 练习2:使用fp.flowRight()、fp.prop()和fp.first()获取第一个参数的name 解: ```javascript let getFirstToName = fp.flowRight(fp.prop('name'), fp.first); ``` ![](E:\webLearn\fed-e-task-01-01\image\02-02.png) #### 练习3:使用帮助函数_average重构averageDollarValue,使用函数组合的方式实现 ```javas let _average = function (xs) { return fp.reduce(fp.add, 0, xs) / xs.length }// <- 无须改动 let averageDollarValue = function (cars) { let dollar_values = fp.map(function (car) { return car.dollar_value }, cars) return _average(dollar_values) } ``` 解: ```javascript let averageDollarValue2 = fp.flowRight(_average,fp.map(car=>car.dollar_value)) ``` ![](E:\webLearn\fed-e-task-01-01\image\02-03.png) #### 练习4:使用flowRight 写一个sanitizeNames()函数,返回一个下划线连接的小写字符串,把数组中的name转换为这种形式:例如:sanitizeNames(["Hello World"])=>["hello_world"] ```javascript let _underscore = fp.replace(/\W+/g,'_') // <--无须改动,并在 sanitizeNames中使用它 ``` 解: ```java const sanitizeNames = fp.map(fp.flowRight(_underscore,fp.toLower)) //下面直接传入cars的处理 let sanitizeNames = fp.flowRight(fp.map(_underscore), fp.map(car => car.name)) ``` ![](E:\webLearn\fed-e-task-01-01\image\02-04.png) ### 三、基于下面提供的代码,完成后续的四个练习 ```java //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 ```javas //app.js const fp = require('lodash/fp') const {Maybe, Container} = require('./support') let maybe = Maybe.of([5, 6, 1]) let ex1 = (i) => { //你需要实现的函数 } ``` 解: ```javascript let ex1 = (i) => { return maybe.map(x => fp.map(fp.add(i), x)) } // console.log(ex1(2)) ``` ![](E:\webLearn\fed-e-task-01-01\image\03-01.png) #### 练习2:实现一个函数ex2,能够使用fp.first获取列表的第一个元素 ```javascript //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 = (key) => { //你需要实现的函数 } ``` 解: ```javascript let ex2 = (key) => { return xs.map(fp.first)._value } // console.log(ex2()) ``` ![](E:\webLearn\fed-e-task-01-01\image\03-02.png) #### 练习3:实现一个函数ex3,使用safeProp 和 fp.first 找到user的名字的首字母 ```javas //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 = (key) => { //你需要实现的函数 } ``` 解: ```javascript let ex3 = (key) => { return fp.flowRight(fp.map(fp.first),safeProp(key)) } // console.log(ex3('name')(user)) ``` ![](E:\webLearn\fed-e-task-01-01\image\03-03.png) #### 练习4:使用Maybe重写ex4,不要有if语句 ```javascript //app.js const fp = require('lodash/fp') const {Maybe, Container} = require('./support') let ex4old = function (n) { if (n) { return parseInt(n) } } ``` 解: ```javascript let ex4 = n => Maybe.of(n).map(parseInt) // console.log(ex4({bro:2})) ``` ![](E:\webLearn\fed-e-task-01-01\image\03-04.png) ### 四、手写实现MyPromise 源码 要求:尽可能还原Promise中的每一个API,并通过注释的范式描述思路和原理 解:详见MyPromise.js