一、谈谈对JS异步编程的理解,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务?
首先,由于JS是单线程的,这样执行任务会发生线程阻塞。所有JS引入了异步编程,通过回调的方式来解决这种阻塞。
其次,对于像定时器这种异步任务以及IO任务、其它线程发送过来的任务,JS会将其放到消息队列中,通过EventLoop的机制从消息队列里面依次取出任务执行。
最后消息队列里的任务就是宏任务,微任务是promise、mutationObserver、nextTick。每一个宏任务都会配置一个微任务队列,微任务队列的执行时机是当前宏任务执行完毕、主线程退出之前。
二、将下面异步代码使用Promise的方式改进
(1)
setTimeout(()=>{
var a = 'hello ';
setTimeout(()=>{
var b = 'lagou '
setTimeout(()=>{
var c = 'i 💓 u'
console.log(a+b+c);
},10)
},10)
},10)
答:
let promise = new Promise((resolve,reject)=>{
resolve('hello ')
}).then(res=>{
return res + 'lagou '
}).then(res=>{
return res + 'i love u'
}).then(res=>{
console.log(res);
})
(2)基于以下代码完成下面4个练习
const fp = require('lodash/fp')
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
}
]
2.1 使用函数组合fp.flowRight()重新实现下面函数
let isLastInStock = function(cars){
let last_car = fp.last(cars)
return fp.prop('in_stock',last_car)
}
答:
const fn = fp.flowRight(fp.prop('in_stock'),fp.last);
2.2 使用fp.flowRight() fp.prop() fp.first()获取第一个car的name
const fn = fp.flowRight(fp.prop('name'),fp.first)
2.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((cars)=>{
return cars.dollar_value
},cars)
return _average(dollar_values)
}
答:
const total = cars=>fp.map(cars=>cars.dollar_value,cars)
const fn = fp.flowRight(_average,total);
console.log(fn(cars));
2.4 使用flowRight写一个sanitizeNames()函数,返回一个下划线连接的小写字符串,把数组中的name转换成这种形式。
let _underscore = fp.replace(/\W+/g,'_');
const sanitizeNames = fp.flowRight(fp.map(_underscore),fp.map(fp.toLower),fp.map(car=>car.name))
console.log(sanitizeNames(cars));
三、基于下面提供的代码,完成以下四个练习
class Container {
static of(val) {
return new Container(val)
}
constructor(val) {
this._val = val
}
map(fn) {
return Container.of(fn(this._val))
}
}
class Maybe {
static of(x) {
return new Maybe(x)
}
isNothing() {
return this._val === null || this._val === undefined
}
constructor(x) {
this._val = x
}
map(fn) {
return this.isNothing() ? this : Maybe.of(fn(this._val))
}
}
module.exports = {Maybe ,Container }
3.1 使用fp.add(x,y) fp.map(f,x)创建一个能让functor里的值增加的函数exl
let maybe = Maybe.of([5, 6, 1])
let exl = (x) => {
return maybe.map(fp.map(a => fp.add(a, x)))
}
console.log(exl(2));
3.2 实现一个函数ex2 ,能使用fp.first获取列表的第一个元素
let xs = Container.of(['do','ray','me','fa','so','la','ti','do'])
let ex2 = ()=>{
return xs.map(fp.first)
//.map(item=>console.log(item))
}
3.3 实现一个函数ex3,使用safeProp和fp.first找到user的名字的首字母。
let safeProp = fp.curry((x,o)=>Maybe.of(o[x]))
let user = {id:2,name:'Albert'}
let ex3 = ()=>{
let safe = safeProp('name',user)
let names = safe.map(name=>name.split('')).map(fp.first)
return names
}
console.log(ex3());
3.4 使用Maybe重写ex4 不要有if语句
// let ex4 = (n)=>{
// if(n){
// return parseInt(n)
// }
// }
let ex4 = (n)=>{
return Maybe.of(n).map(parseInt)
}
console.log(ex4(3.5));
四、手写Promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.rejected)
} catch (error) {
this.rejected(error)
}
}
// 状态
status = PENDING;
// 成功后的值
value = undefined;
// 失败后的原因
err = undefined;
// 成功回调
successCb = [];
// 失败回调
failCb = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED;
this.value = value;
// this.successCb && this.successCb(this.value)
while (this.successCb.length) {
this.successCb.shift()()
}
}
rejected = err => {
if (this.status !== PENDING) return
this.status = REJECTED;
this.err = err;
// this.failCb && this.failCb(this.err)
while (this.failCb.length) {
this.failCb.shift()()
}
}
then(successCb, failCb) {
successCb = successCb ? successCb : value => value;
failCb = failCb ? failCb : err => { throw err }
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCb(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCb(this.err)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
//等待
this.successCb.push(() => {
setTimeout(() => {
try {
let x = successCb(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
});
this.failCb.push(() => {
setTimeout(() => {
try {
let x = failCb(this.err)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
});
}
})
return promise2;
}
catch(cb){
return this.then(undefined,cb)
}
finally(cb) {
return this.then(value => {
return MyPromise.resolve(cb()).then(() => value);
}, err => {
return MyPromise.resolve(cb()).then(() => { throw err })
})
}
static all(arr) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index++;
if (index === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i];
if (current instanceof MyPromise) {
current.then(value => addData(i, value), err => reject(err))
} else {
addData(i, arr[i])
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
} else {
return new MyPromise((resolve) => resolve(value))
}
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('重复引用了'))
}
if (x instanceof MyPromise) {
// x.then(value=>resolve(value),err=>reject(err))
x.then(resolve, reject)
} else {
resolve(x)
}
}
博客围绕JS异步编程展开,介绍了因JS单线程易阻塞而引入异步编程,通过EventLoop从消息队列取任务执行,区分了宏任务和微任务。还包含用Promise改进异步代码的练习,以及基于给定代码完成多个函数实现练习,最后涉及手写Promise。
873

被折叠的 条评论
为什么被折叠?



