异步
异步概念
有很多场景存在。
setTimeout 会放到代码结束之后执行。
异步不会阻塞后面程序执行
单线程
var a = truesetTimeout(function(){a=false},100)while(true){console.log('x')}
因为js是单线程的,进入while之后会死循环,没有线程去跑定时器。
异步的场景
- 定时器。setTimeout setInterval
- 网络请求
- promise
- async/await
定时器
settimeout0 不是马上执行,是单线程的js忙完了其他逻辑才运行,是异步的
可以考虑 requestAnimationFrame 这个函数自带节流 16.6ms
promise
除了Promise,同一时期的计算机科学家还使用了“终局”(eventual)、“期许”(future)、“延迟”(delay)和“迟付”(deferred)等术语指代同样的概念。所有这些概念描述的都是一种异步程序执行的机制。
经过一段时间的发展,最终规定了 Promses/A+规范,也称为了 ES6 规范实现的范本。
api
Proimse 本身是引用类型,可以通过 new 来实例化。参数传入执行器。
实例状态机:
- pending 待定,进行中
- fulfilled/resolved/settled 解决、兑现
rejected 拒绝
pending 本身不一定非得变为另一个状态,但变到另外一个状态,不可再改变。
- pending 的过程本身是私有的,不能被修改,不能检测。
实例打印
构造函数打印
在谈论具体api时候,我们假想存在下面的函数:
class Promise{then(){}catch(){}finally(){}static all(){} // 一组Promise全部解决之后再解决static allSettled(){} //static race(){} // 一组Promise中最先出结果的无论是res还是rej的static reject(){}static resolve(){}}
EventLoop
浏览器中的 eventloop
js遇到异步函数,会放到task里,等到当前执行队列空,开始执行task。
本质上,异步还是同步演变。
task分为两种:
- 微观任务micro task 称为 job
- 宏观任务 marco task 称为 task
console.log('script start') // 1async function async1() {await async2()// 去下一个 让出来console.log('async1 end')//7}async function async2() {console.log('async2 end')//2}async1()setTimeout(function() {console.log('setTimeout')//9}, 0)new Promise(resolve => {console.log('Promise') //3resolve()}).then(function() {console.log('promise1')//5}).then(function() {console.log('promise2')//6})console.log('script end') //4
观察这段代码。1-4 5-9
1-2牢记promise await是回调。
2-3-4 顺序执行 promise
然后继续执行 promise的回调 5-6
7 promise任务结束,继续回调
9 settimeout
总结:
- 先执行同步代码,这是宏观任务。
- 同步代码结束,当前执行队列空,看异步代码
- 执行微观任务
- 渲染页面
- 执行完微观任务,回到宏观任务执行settimeout等
所以,promise和 setTimeout 比,promise是微观任务先执行
微观任务 process.nextTick promise MutationObserver
宏观任务 script setTimeout setInterval setImmediate I/O UI Rendering
node中的 event loop
和浏览器完全不同
node分为六个阶段,反复执行
timers — pending callbacks — idle,prepare — poll — check — close callbacks
timer
执行 setTimeout setInterval
I/O
处理上一轮循环中少数未执行的I/O 回调
poll
- 回调timer阶段
- 执行 io 回调
慢慢看吧。
- 高阶函数,异步问题
- 发布订阅、观察者模式
- Promise应用
- 实现
- 面试题
- 扩展
- generator和co库
- async/await
高阶函数
这个函数式高阶函数
- 一个函数的参数是一个函数,比如回调函数
- 一个函数返回一个函数
应用场景
扩展业务代码。
假设我们有一个代码想要拓展
// 默认参数function say(){console.log('say')}// 补充before方法Function.prototype.before = function(cb){return ()=>{cb()this()}}let beforeSay = say.before(()=>console.log('before say'))beforeSay()
发布订阅 观察者
如果你看过 vue2 的源码,对下面的东西你会感兴趣
发布
let event = {arr:[],on(fn){this.arr.push(fn)},emit(){this.arr.forEach(fn=>fn())}}
我们维护了一个数组,先订阅,再发布
观察者模式
观察者和被观察者,被观察者发生变化需要通知。
也需要收集和通知。存在关联
// 小宝宝class Subject {constructor(name){this.name = namethis.state = 'happy'this.observers = [] // 观察者}setState(state){this.state = state// 调用观察者的方法this.observers.forEach(o=>o.update(this))}attach(o){this.observers.push(o) // 订阅}}var baby = new Subject('name')class Observer{constructor(name){this.name=name}update(instance){// 在这里就拿到了观察者的实例}} // 父母var father = new Observer('father')var mother = new Observer('mother')baby.attach(father)baby.attach(mother)baby.stetState('cry')
和vue太像了,以后用来举例子。
Promise/A+ 标准被社区支持。Promise 是一种状态机,只会是三种方式的一种。
-1 参考链接
- 高级程序设计 第四版
