javascript的单线程理解:
- 首先来说javascript是基于浏览器的,也被叫做浏览器语言,而浏览器是多线程内核的,一般有以下常驻线程:
- 渲染引擎线程:该线程负责渲染浏览器页面
- JS引擎线程:该线程负责JS的解析和执行
- 定时触发器线程:处理定时事件,比如setTimeout,setInterval
- 事件触发线程:处理DOM事件
- 异步http请求线程:处理http请求
- 注意:渲染线程和JS引擎线程不能同时进行
JS引擎线程负责JS,负责JS代码的解析和执行,而Javascript之所以是单线程是因为浏览器在运行的时候之开启了一个JS引擎线程来解析和执行JS。
所以我们应该知道的是因为为了避免操作DOM时产生混乱,浏览器只会开启一个JS引擎线程,而与I/O操作、定时器的计时和事件监听…等都是由浏览器提供的其他线程完成的。
同步Synchronous
与异步Asynchronous
:
引用一个例子理解同步和异步的关系:在公路上,汽车一辆接一辆,有条不紊的在a:一条主道路上单向运行。这时,有b:一辆车坏掉了。假如它停在原地进行修理,那么后面的车就会被堵住没法行驶,交通就乱套了。幸好旁边有c:应急车道,可以把d:故障车辆推到应急车道e:修理,而正常的车流不会受到任何影响。等车修好了,再f:从应急车道回到正常车道即可。唯一的影响就是,应急车道用多了,原来的车辆之间的顺序会有点乱
理解:
a:js引擎的主线程;
b:主线程当中执行的一个同步任务;
c:任务队列(不在主线程);
d:一个异步任务;
e:将一个异步任务放入消息队列;
f:异步任务需等待主线程栈中所有任务执行完后,由事件循环机制将一个异步任务放进主线程
任务队列和事件循环
任务队列(消息队列) 是一个先进先出的队列,它里面存放着各种消息–>回调函数可以是一个消息
事件循环 是指主线程重复从消息队列中取出消息然后执行的循环执行机制,即基于Event LOOP:
1
2什么是Event LOOP:
https://www.ruanyifeng.com/blog/2013/10/event_loop.html
理解一些异步操作(异步编程)
我们已经知道javascript是单线程执行任务,即后一个任务必须等待前一个任务的完成,但是我们必须这样吗?考虑到效率就需要一些异步操作,即可以实现将一些耗时的任务比如等待文件的读取挂起来(进入任务队列),再进行下一个任务的执行,知道文件的读取有了结果或者响应后,再回过头执行任务队列的任务。
有以下几种方式可以实现异步编程:
- 回调函数
- 事件监听
- 发布/订阅
- promise
- generator(ES6)
- async/await(ES7)
回调函数
回调函数是实现异步最简单的操作和最基本的方法:
1 | 1.异步操作前: |
上面的代码意图是顺序执行fn1、fn2和fn3函数
但是如果fn2可以视作一个延迟了500毫秒执行的异步函数,也就是说fn2的函数会被挂起而进入任务队列等待后面fn3函数执行完毕后fn2再执行
所以我们想要保持原来的意图,即fn1执行后然后执行fn2再执行fn3的这个顺序,于是我们这儿可以使用回调函数解决:
1 | //使用回调函数改变代码结构 |
这样就达到了最初的意图-fn1,fn2,fn3依次执行
但是fn2和fn3完全耦合在一起,如果有多个类似的函数,很有可能出现fn1(fn2(fn3(fn4(…))))这样的情况,这就是回调地狱
(多个回调函数嵌套的情况)。
Promise
Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口,也就是为解决回调函数噩梦而提出的写法–>将回调函数的横向加载变成纵向加载。
首先来说Promise是一个对象,也是一个构造函数
理解Promise机制:Promise是一个代理对象,这个值可以称为Promise对象的状态,而Promise对象就是通过自身的状态来控制异步函数–>Promise实例具有三种状态(PromiseStatus):
- 异步操作未完成(pending): promise暂时还没有被解决也没有被拒绝,仍然处于pending状态
- 异步操作成功(fulfilled):promise已经被resolved没有发生错误
- 异步操作失败(rejected):promise已经被rejected,出现错误
我们可以通过一个new一个Promise:
1 | //通常我们是通过new一个Primise对象,然后传入一个函数(这里是匿名函数) |
对于一个promise, 我们可以使用它上面的三个方法:
·then(): 在一个promise被resolved后调用,内部有两个方法:
1
2
3
4
5
6promise.then(function onFulfilled(value){ console.log(value);//return undefined },
function onRejected(error){ console.error(error);//return undefined})
//我们在使用.then多次调用形成一个调用链时,比如:promise.then(step2).then(step3)....then(stepn)。每个then返回的都必须是一个promise对象,假如then方法里面的onFulfilled函数返回的不是promise,比如是Number或string,那么架构会用Promise.resolve(return的返回值)包装成一个resolved状态的promise返回
//一般只会使用resolve,也就是只在传入一个then中传入一个匿名函数.catch(): 在一个promise被rejected后被调用
.finally(): 不论promise是被resolved还是reject总是调用
用法:
1 | //1.以加载图片压缩图片、为图片应用过滤器并保存它的例子说明: |
“微任务”:
Promise 的回调函数属于异步任务,准确来说是不正常的异步任务(微任务),执行顺序在同步任务和正常异步任务之间:
1 | setTimeout(function() { |
Async/Await
参考:
异步操作概述:
https://wangdoc.com/javascript/async/general.html
js中的异步与同步:
https://www.cnblogs.com/Yellow-ice/p/10433423.html
JavaScript异步机制详解:
https://blog.csdn.net/LRH0211/article/details/79172822
JavaScript Promise 和Async/Await一看就懂:
https://blog.csdn.net/qq_36174666/article/details/106353457
js异步操作、事件监听、发布-订阅模式、Generator函数:
https://zhuanlan.zhihu.com/p/67629425
浅析js中的Promise和async/await:
https://blog.csdn.net/yes1983/article/details/83629647