JavaScript 深度剖析-模块一-作业

简答题

一、谈谈你是如何理解JS异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务?

js异步编程
因为早起的js主要是处理页面的交互,其核心就是DOM操作,这决定了js的引擎是以单线程模式执行js代码。
这就会出现一个问题,假如在执行的过程中,需要了一个耗时特别就的任务,就会阻塞后面的代码执行。
为了解决这耗时任务阻塞执行的问题,js将任务的执行模式分成了两种:
同步模式,异步模式。
同步模式,就是任务排队依次执行。
异步模式,就是通过回调函数的形式将所要执行的函数,放到任务队列中,不占用主线程,只有等主线程执行完毕后,才通知请求执行任务,然后才将任务从任务队列中加入到主线程中执行。

EventLoop
事件循环,是我们使用异步的原理,是指浏览器一种解决JS单线程运行时的一种机制。
它主要是负责监听调用栈Call stack和消息队列
一旦Call stack调用栈里面的任务结束了,它就开始工作了。

消息队列
消息队列是一种数据结构,主要是存放那些异步的回调任务的。

宏任务&微任务
ES6 规范中,microtask 称为 jobs,macrotask 称为 task
宏任务是由宿主发起的,消息队列中的每个任务都是宏任务,而微任务由JavaScript自身发起。
执行栈在完成同步任务之后,会去执行任务队列中的宏任务,每次宏任务执行完毕之后,查看相应的微任务队列是否为空,如果不为空,则会按照先进先出的规则全部执行完对应的微任务,如此循环,直至任务结束。

代码题

一、将下面异步代码使用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 fn(value) {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(value)
        }, 10)
    })
    return promise
}
fn().then(() => {
    return fn('hello')
}).then((value) => {
    return fn(value + 'lagou')
}).then((value) => {
    return fn(value + 'I ❤️ U')
}).then((value) => {
    console.log(value)
})

// 另一种方式
Promise.resolve()
.then(()=>{
    return 'hello'
})
.then(value=>{
    return value + 'lagou'
})
.then(value=>{
    console.log(value + 'I ❤️ U')
})

二、基于以下代码完成下面的四个练习

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: 1850000, in_stock: true},
  {name:'Pagani Huayra', horsepower: 700, dollar_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)
}
// => 解答
let isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last)
console.log(isLastInStock(cars))

// 练习2:使用fp.flowRight()、fp.prop()和fp.first()获取第一个car的name
// => 解答
let firstCarName = fp.flowRight(fp.prop('name'), fp.first)
console.log(firstCarName(cars))

// 练习3:使用帮助函数_average重构averageDollarValue,使用函数组合的方式实现
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)
}
// => 解答
let averageDollarValue = fp.flowRight(_average,fp.map(car => car.dollar_value))
console.log(averageDollarValue(cars))

// 练习4:使用flowRight写一个sanitizeNames()函数,返回一个下划线连接的小写字符串,把数组中的name转换为这种形式:
// 例如:sanitizeNames(["Hello World"]) => ["Hello_world"]
let _underscore = fp.replace(/\W+/g, '_') // => 无须改动
// => 解答
let sanitizeNames = fp.map(fp.flowRight(_underscore, fp.toLower));
console.log(sanitizeNames(["Hello World","Javascript Code"]) )

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

// 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
// app.js
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let maybe = Maybe.of([5, 6, 1])
let ex1 = () => {
	// 你需要实现的函。。。
}
// => 解答
let ex1 = (num) => {
  let fn = fp.flowRight(fp.map(fp.add(num)))
  return maybe.map(fn)
}
console.log(ex1(4))

// 练习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 xs.map(fp.first)._value
}
console.log(ex2())

// 练习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 = () => {
  return safeProp('name', user).map(fp.first)._value
}
console.log(ex3())

// 练习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) {
  let m1 = new Maybe(n)
  let m2 = m1.map(parseInt)
  return m2._value
}
console.log(ex4())
console.log(ex4(34))

四、手写实现MyPromise源码

要求:尽可能还原Promise中的每一个API,并通过注释的方式描述思路和原理。

/*
 * 1、promise是一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行
 * 2、Promise中有三个状态,分别为 成功 resolve、失败 reject、等待 pedding
 *    状态一旦确定就不能被改变
 *    pedding-resolve
 *    pedding-reject
 * 3、resolve和reject函数是用来更改状态的
 *    resolve:fufilled
 *    reject:rejected
 * 4、then方法做的事情就是判断状态,如果状态是成功,调用成功回调函数,如果是失败,调用失败函数,then方法是被定义在原型对象中
 * 5、then成功回调有一个参数,表示成功之后的值,失败回调有一个参数,表示失败的原因
 */
const PEDDING = 'pedding' //等待
const FUFILLED = 'fufilled' //成功
const REJECT = 'reject' //失败

class MyPromise {
    constructor(exeuctor) {
        try {
            exeuctor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }

    status = PEDDING
    //成功之后的值
    value = undefined
    //失败之后的原因
    reason = undefined
    //成功回调
    // successCallback = undefined  只能处理一个回调函数
    successCallback = []
    //失败回调
    // failCallback = undefined
    failCallback = []


    //使用箭头函数定义是为了执行方法的时候让this指向MyPromise的实例对象
    resolve = value => {
        //如果状态不是等待,向下执行
        if (this.status !== PEDDING) return
        this.status = FUFILLED
        //保存成功之后的值
        this.value = value
        //判断成功回调是否存在,如果存在则调用
        // this.successCallback && this.successCallback(this.value)
        while (this.successCallback.length) {
            // this.successCallback.shift()(this.value)
            this.successCallback.shift()()
        }
    }

    reject = reason => {
        if (this.status !== PEDDING) return
        this.status = REJECT
        //保存失败后的原因
        this.reason = reason
        // this.failCallback && this.failCallback(this.reason)
        while (this.failCallback.length) {
            // this.failCallback.shift()(this.reason)
            this.failCallback.shift()()
        }
    }

    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FUFILLED) {
                // let x = successCallback(this.value)
                /**
                 * 需要判断x的值是普通值还是promise对象,如果是普通值,直接调用resolve,
                 * 如果是promise对象,查看promise的结果,根据promise对象返回的结果决定调用resolve,reject
                 */
                // resolvePromise(x,resolve,reject)
                //防止循环调用,但是此时promise2并不能获取到,所以现在需要使其变成异步执行代码
                // resolvePromise(promise2,x,resolve,reject)
                //使用try-catch捕获异常
                try {
                    setTimeout(() => {
                        let x = successCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    }, 0)
                } catch (error) {
                    reject(error)
                }
            } else if (this.status === REJECT) {
                setTimeout(() => {
                    let x = failCallback(this.reason)
                    resolvePromise(promise2, x, resolve, reject)
                }, 0)
            } else {
                //状态为pedding,等待
                // 将成功回调和失败回调存储起来
                // this.successCallback.push(successCallback)
                this.successCallback.push(() => {
                    setTimeout(() => {
                        let x = successCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    }, 0)
                })
                // this.failCallback.push(failCallback)
                this.failCallback.push(() => {
                    setTimeout(() => {
                        let x = failCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    }, 0)
                })
            }
        })
        return promise2
    }

    finally(callback){
        return this.then(value=>{
            return MyPromise.resolve(callback()).then(()=>value)
        },reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }

    catch(failCallback){
        return this.then(undefined,failCallback)
    }


    static all(array) {
        let result = []
        
        return new MyPromise((resolve, reject) => {
            let count = 0
            function addData(index,value){
                result[index] = value
                count++
                console.log(count,array.length)
                if(count === array.length){
                    resolve(result) 
                }   
            }
            for(let i= 0;i<array.length;i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    //Promise对象
                    current.then((value)=>{
                        addData(i,value)
                    },(reason)=>{
                        reject(reason)
                    })
                }else{//普通值
                    addData(i,current)
                }
            }
        })
    }


    static resolve(value){
        if(value instanceof MyPromise){
            return value
        }
        return new MyPromise(resolve=>resolve(value))
    }

}

function resolvePromise(promise, x, resolve, reject) {
    if (promise === x) {
        return reject(new TypeError("Chaining cycle detected for promise #<Promise>    "))
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

module.exports = MyPromise
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值