js延时函数_【大前端01-01】函数式编程与JS异步编程、手写Promise

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

如何理解JS异步编程

众所周知JavaScript语言执行环境是“单线程”(单线程,就是指一次只能完成一件任务,如果有多个任务就必须排队等候,前面一个任务完成,再执行后面一个任务)。这种“单线程”模式执行效率较低,任务耗时长。 为了解决这个问题,提出了“异步模式”(异步模式,是指后一个任务不等前一个任务执行完就执行,每个任务有一个或多个回调函数)。 异步模式使得JavaScript在处理事务时非常高效,但也带来很多问题,如异常处理困难、嵌套过深。

EventLoop是做什么的

  • event loop是一个执行模型,在不同的地方有不同的实现。浏览器和NodeJS基于不同的技术实现了各自的Event Loop。
    • 浏览器的Event Loop是在html5的规范中明确定义。
    • NodeJS的Event Loop是基于libuv实现的。
    • libuv已经对Event Loop做出了实现,而HTML5规范中只是定义了浏览器中Event Loop的模型,具体的实现留给了浏览器厂商。

浏览器的Event Loop

ccbce24543fe95629e461c5c4f8f475d.png

这张图将浏览器的Event Loop完整的描述了出来,我来讲执行一个JavaScript代码的具体流程: 1. 执行全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等); 2. 全局Script代码执行完毕后,调用栈Stack会清空; 3. 从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1; 4. 继续取出位于队首的任务,放入调用栈Stack中执行,以此类推,直到直到把microtask queue中的所有任务都执行完毕。注意,如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行; 5. microtask queue中的所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空; 6. 取出宏队列macrotask queue中位于队首的任务,放入Stack中执行; 7. 执行完毕后,调用栈Stack为空; 8. 重复第3-7个步骤; 9. ......

可以看到,这就是浏览器的事件循环Event Loop

这里归纳3个重点: 1. 宏队列macrotask一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务; 2. 微任务队列中所有的任务都会被依次取出来执行,直到microtask queue为空; 3. 图中没有画UI rendering的节点,因为这个是由浏览器自行判断决定的,但是只要执行UI rendering,它的节点是在执行完所有的microtask之后,下一个macrotask之前,紧跟着执行UI render。

在执行微队列microtask queue中任务的时候,如果又产生了microtask,那么会继续添加到队列的末尾,也会在这个周期执行,直到microtask queue为空停止。

注:当然如果你在microtask中不断的产生microtask,那么其他宏任务macrotask就无法执行了,但是这个操作也不是无限的,拿NodeJS中的微任务process.nextTick()来说,它的上限是1000个,这里不再详细讲。

  • 总结:
  • 浏览器的Event Loop和NodeJS的Event Loop是不同的,实现机制也不一样,不要混为一谈,今天我们只介绍浏览器里面的Event Loop。
  • 浏览器可以理解成只有1个宏任务队列和1个微任务队列,先执行全局Script代码,执行完同步代码调用栈清空后,从微任务队列中依次取出所有的任务放入调用栈执行,微任务队列清空后,从宏任务队列中只取位于队首的任务放入调用栈执行,注意这里和Node的区别,只取一个,然后继续执行微队列中的所有任务,再去宏队列取一个,以此构成事件循环。

消息队列是做什么的

消息队列:也称为任务队列,是一个先进先出的队列,它里面存放着各种消息,即异步操作的回调函数,异步操作会将相关回调添加到任务队列中,而不同的异步操作添加到任务队列的时机也不同,如onclick,setTimeout,ajax处理的方式都不同,这些异步操作都是由浏览器内核的不同模块来执行的:

  1. onclick由浏览器内核的DOM Binding模块来处理,当事件触发的时候,回调函数会立即添加到任务队列中;
  2. setTimeout会由浏览器内核的timer模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中;
  3. ajax会由浏览器内核的network模块来处理,在网络请求完成返回之后,才将回调添加到任务队列中;

什么是宏任务

  • 宏任务/宏队列,macrotask,也叫tasks。 一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:
    • setTimeout
    • setInterval
    • setImmediate (Node独有)
    • requestAnimationFrame (浏览器独有)
    • I/O
    • UI rendering (浏览器独有)

什么是微任务

  • 微任务/微队列,microtask,也叫jobs。 另一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:
    • process.nextTick (Node独有)
    • Promise
    • Object.observe
    • MutationObserver
    • queueMicroTask

宏任务与微任务的区别

这个就像去银行办业务一样,先要取号进行排号。 一般上边都会印着类似:“您的号码为XX,前边还有XX人。”之类的字样。

因为柜员同时只能处理一个来办理业务的客户,这时每一个来办理业务的人就可以认为是银行柜员的一个宏任务来存在的,当柜员处理完当前客户的问题以后,选择接待下一位,广播报号,也就是下一个宏任务的开始。 所以多个宏任务合在一起就可以认为说有一个任务队列在这,里边是当前银行中所有排号的客户。 任务队列中的都是已经完成的异步操作,而不是说注册一个异步任务就会被放在这个任务队列中,就像在银行中排号,如果叫到你的时候你不在,那么你当前的号牌就作废了,柜员会选择直接跳过进行下一个客户的业务处理,等你回来以后还需要重新取号。

而且一个宏任务在执行的过程中,是可以添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P爆雷有点儿多,是不是要选择稳一些的理财呢”,然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。 所以本来快轮到你来办理业务,会因为老大爷临时添加的“理财业务”而往后推。 也许老大爷在办完理财以后还想 再办一个信用卡?或者 再买点儿纪念币? 无论是什么需求,只要是柜员能够帮她办理的,都会在处理你的业务之前来做这些事情,这些都可以认为是微任务。

在当前的微任务没有执行完成时,是不会执行下一个宏任务的。

【代码题】一、将下面异步代码使用Promise的方式改进

setTimeout

解答:

function 

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

const 

练习1:使用函数组合fp.flowRight()重新实现下面这个函数

let 

解答:

let 

练习2:使用fp.flowRight()、fp.prop()和fp.first()获取第一个car的name

解答:

let 

练习3:使用帮助函数_average重构averageDollarValue,使用组合函数的方式实现

let 

解答:

//第一种

练习4:使用flowRight写一个sanitizeNames()函数

返回一个下划线连接的小写字符串,把数组中的name转换为这种形式:例如:sanitizeNames(["Hello World"])=>["hello_world"]

let 

解答:

//let _underscore = fp.replace(/w+/g, '_') // 不符合题意 应该为s

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

// support.js

练习1:使用fp.add(x,y)和fp.map(f,x)创建一个能让functor里的值增加的函数ex1

// app.js

解答:

return 

练习2:实现一个函数ex2,能够使用fp.first获取列表的第一个元素

// app.js

解答:

return 

练习3:实现一个函数ex3,使用safeProp和fp.first找到user的名字的首字母

// app.js

解答:

return 

练习4:使用Maybe重写ex4,不要有if语句

// app.js

解答:

let 

【代码题】四、手写实现MyPromise源码

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

解答:

/*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值