# fed-e-task-01-01 **Repository Path**: feilian/fed-e-task-01-01 ## Basic Information - **Project Name**: fed-e-task-01-01 - **Description**: part1 模块一作业 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-27 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 模块一:函数式编程与JS异步编程、手写Promise ### 简答题 #### 一、谈谈你是如何理解JS异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务? 1. JS异步编程 1. 什么是: 处理JS程序中将来运行的部分的编程方式 2. 为什么: JS语言的执行环境是单线程的(由JS的执行环境决定,因为要处理大量的I/O操作,避免出现线程同步的问题), 一次只能完成一个任务。如果有多个任务就必须要排队,前面一个任务完成,再执行后面一个任务。虽然避免了线程同步的问题, 但是只要有一个任务耗时很长,就会拖延整个程序的执行。为了解决这个问题,javascript语言将任务的执行模式分为两种:同步和异步。 3. 如何做 1. 回调函数 2. 事件监听 3. 发布订阅 4. promise/A+ 5. 生成器 Generators/yield 6. async/await 2. EventLoop 1. 什么是:事件循环是异步编程的实现方式之一。进程启动之后就进入主循环,主循环的过程就是不停的从事件队列里面读取事件。 3. 消息队列 1. 什么是:异步过程中,工作线程在异步操作完成后需要通知主线程,工作线程将消息放到消息队列中,主线程通过事件循环过程去取消息 4.宏任务(macrotask )和微任务(microtask ) 1. macrotask 和 microtask 表示异步任务的两种分类。 2. 在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。 ### 代码题 #### 一、将下面异步代码使用Promise的方式改进 ``` javascript setTimeout(function () { var a = 'hello'; setTimeout(function () { var b = 'lagou'; setTimeout(function () { var c = 'I ♥ U'; console.log(a + b + c); }, 10); }, 10); }, 10); ``` #### 解答 ``` javascript var promise1 = new Promise((resolve, rejected) => { console.log(resolve); resolve('hello'); }); promise1.then((value) => { console.log(value); return 'hello'; }) .then(value => { console.log(value + 'lagou') return value + 'lagou'; }) .then(value => { console.log(value + 'I ♥ U') return value + 'I ♥ U'; }) .then(value => { console.log(value) return value + 'I ♥ U'; }); ``` 执行结果: #### 二、基于以下代码完成下面的四个联系 ``` javascript // 数据 // horsepower 马力, doller_value 价格, in_stock 库存 const fp = require('lodash/fp'); 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: 1142000, 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: true}, ] ``` ##### 练习1:使用函数组合fp.flowRight() 重新实现下面这个函数 ``` javascript let isLastInStock = function (cars) { // 获取最后一条数据 let last_car = fp.last(cars); // 获取最后一条数据的 in_stock 属性值 return fp.prop('in_stock', last_car); } let r = isLastInStock(cars); ``` ##### 解答 ``` javascript let isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last); let r = isLastInStock(cars); console.log(r); ``` ##### 练习2: 使用fo.flowRight(), fp.prop() 和 fp.first() 获取第一个car 的 name ``` javascript const trace = fp.curry((tag, value) => { console.log(tag, value); return value; }); let isFirstInName = fp.flowRight(fp.prop('name'), trace('first'), fp.first); let f = isFirstInName(cars); console.log(f); ``` ##### 练习3: 使用帮助函数 _average重构averageDollerValue,使用函数组合的方式实现 ``` javascript let _avarage = function (xs) { return fp.reduce(fp.add, 0, xs) / xs.length; } // <- 无须改动 let averageDollerValue = function (cars) { let doller_values = fp.map(function (car) { return car.doller_value; }, cars); console.log(doller_values); return _avarage(doller_values); } ``` ##### 解答 ``` javascript let averageDollerValue = fp.flowRight(_avarage ,fp.map(car => car.doller_value)); console.log(averageDollerValue(cars)); ``` ##### 练习4: 使用flowRight 写一个sanitizeNames() 函数,返回一个下划线连接的小写字符串,把数组中的name转换为这种形式:例如: ``` javascript sanitizeNames(["Hello World"]) => ["hello_world"] let _underscore = fp.replace(/\W+/g, '_') // <-- 无须改动,并在sanitizeNames 中使用它 ``` ##### 解答 ``` javascript let sanitizeNames = fp.flowRight(fp.split(','), fp.toLower, fp.map(car => _underscore(car.name))); console.log(sanitizeNames(cars)); ``` #### 三、基于下面提供的代码,完成后续的四个练习 #### supports.js #### 练习1: 使用fp.add(x, y) 和 fp.map(f, x) 创建一个能让functor 里的值增加的函数ex1 ``` javascript // app.js let maybe = Maybe.of([5, 6, 1]); let ex1 = maybe.map(values => { let result = fp.map((val) => { let add = fp.add(1); return add(val); }, values); return result; }); // 简写 // let ex1 = maybe.map(i => fp.map(fp.add(1), i)) console.log('ex1', ex1); ``` #### 练习2:实现一个函数ex2, 能够使用fp.first获取列表的第一个元素 ``` javascript let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do']); let ex2 = xs.map(values => fp.first(values)); console.log('ex2', ex2); ``` #### 练习3:实现一个函数ex3, 使用safeProp和fp.first找到user的名字和首字母 ``` javascript let safeProp = fp.curry(function (x, o) { return Maybe.of(o[x]); }) let user = { id: 2, name: 'Albert' }; let ex3 = safeProp('name')(user).map(fp.first); console.log(safeProp('name')(user), ex3); ``` #### 练习4:使用Maybe重写ex4,不要有if语句 ``` javascript // let ex4 = function (n) { // if (n) { // return parseInt(n); // } // } let ex4 = function (n) { let maybe = Maybe.of(n); maybe.map(value => { return parseInt(value); }); return maybe; } ex4('234'); console.log(ex4(undefined), ex4('234')); ```