网站的运营方式,在网站建设中logo是指什么,北京计算机编程培训学校,网站推荐2021已知#xff0c;JavaScript 是单线程的#xff0c;天生异步#xff0c;适合 IO 密集型#xff0c;不适合 CPU 密集型#xff0c;但是#xff0c;为什么是异步的喃#xff0c;异步由何而来的喃#xff0c;我们将在这里逐渐讨论实现。一、进程与线程1. 浏览器是多进程的它… 已知JavaScript 是单线程的天生异步适合 IO 密集型不适合 CPU 密集型但是为什么是异步的喃异步由何而来的喃我们将在这里逐渐讨论实现。一、进程与线程1. 浏览器是多进程的它主要包括以下进程Browser 进程浏览器的主进程唯一负责创建和销毁其它进程、网络资源的下载与管理、浏览器界面的展示、前进后退等。GPU 进程用于 3D 绘制等最多一个。第三方插件进程每种类型的插件对应一个进程仅当使用该插件时才创建。浏览器渲染进程(浏览器内核)内部是多线程的每打开一个新网页就会创建一个进程主要用于页面渲染脚本执行事件处理等。2. 渲染进程(浏览器内核)浏览器的渲染进程是多线程的页面的渲染JavaScript 的执行事件的循环都在这个进程内进行GUI 渲染线程负责渲染浏览器界面当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时该线程就会执行。JavaScript 引擎线程也称为 JavaScript 内核负责处理 Javascript 脚本程序、解析 Javascript 脚本、运行代码等。(例如 V8 引擎)事件触发线程用来控制浏览器事件循环注意这不归 JavaScript 引擎线程管当事件被触发时该线程会把事件添加到待处理队列的队尾等待 JavaScript 引擎的处理。定时触发器线程传说中的 setInterval 与 setTimeout 所在线程注意W3C 在 HTML 标准中规定规定要求 setTimeout 中低于 4ms 的时间间隔算为 4ms 。异步 http 请求线程在 XMLHttpRequest 连接后通过浏览器新开一个线程请求将检测到状态变更时如果设置有回调函数异步线程就产生状态变更事件将这个回调再放入事件队列中。再由 JavaScript 引擎执行。注意GUI 渲染线程与 JavaScript 引擎线程是互斥的当 JavaScript 引擎执行时 GUI 线程会被挂起(相当于被冻结了)GUI 更新会被保存在一个队列中等到 JavaScript 引擎空闲时立即被执行。所以如果 JavaScript 执行的时间过长这样就会造成页面的渲染不连贯导致页面渲染加载阻塞。二、单线程的 JavaScript所谓单线程是指在 JavaScript 引擎中负责解释和执行 JavaScript 代码的线程唯一同一时间上只能执行一件任务。问题首先为什么要引入单线程喃我们知道浏览器需要渲染 DOMJavaScript 可以修改 DOM 结构JavaScript 执行时浏览器 DOM 渲染停止如果 JavaScript 引擎线程不是单线程的那么可以同时执行多段 JavaScript如果这多段 JavaScript 都修改 DOM那么就会出现 DOM 冲突。你可能会说web worker 就支持多线程但是 web worker 不能访问 window 对象document 对象等。原因避免 DOM 渲染的冲突当然我们可以为浏览器引入锁 的机制来解决这些冲突但其大大提高了复杂性所以 JavaScript从诞生开始就选择了单线程执行。引入单线程就意味着所有任务需要排队前一个任务结束才会执行后一个任务。这同时又导致了一个问题如果前一个任务耗时很长后一个任务就不得不一直等着。// 实例1let i, sum 0for(i 0; i 1000000000; i ) { sum i}console.log(sum)在实例1中sum 并不能立刻打印出来必须在 for 循环执行完成之后才能执行 console.log(sum) 。// 实例2console.log(1)alert(hello)console.log(2)在实例2中浏览器先打印 1 然后弹出弹框点击确定后才执行 console.log(2) 。总结优点实现比较简单执行环境相对单纯缺点只要有一个任务耗时很长后面的任务都必须排队等着会拖延整个程序的执行。常见的浏览器无响应(假死)往往就是因为某一段 Javascript 代码长时间运行(比如死循环)导致整个页面卡在这个地方其他任务无法执行。为了解决这个问题JavaScript 语言将任务的执行模式分为两种同步和异步三、同步与异步1. 同步func(args...)如果在函数 func 返回的时候调用者就能够得到预期结果(即拿到了预期的返回值或者看到了预期的效果)那么这个函数就是同步的。let a 1Math.floor(a)console.log(a) // 12. 异步如果在函数 func 返回的时候调用者还不能够得到预期结果而是需要在将来通过一定的手段得到那么这个函数就是异步的。fs.readFile(foo.txt, utf8, function(err, data) { console.log(data);});总结 JavaScript 采用异步编程原因有两点一是 JavaScript 是单线程二是为了提高 CPU 的利用率。四、异步过程fs.readFile(data.json, utf8, function(err, data) { console.log(data)})在执行这段代码时fs.readFile 函数返回时并不会立刻打印 data 只有 data.json 读取完成时才打印。也就是异步函数 fs.readFile 执行很快但后面还有工作线程执行异步任务、通知主线程、主线程回调等操作这个过程就叫做异步过程。主线程发起一个异步操作相应的工作线程接受请求并告知主线程已收到(异步函数返回)主线程继续执行后面的任务同时工作线程执行异步任务工作线程完成任务后通知主线程主线程收到通知后执行一定的动作(调用回调函数)。工作线程在异步操作完成后通知主线程那么这个通知机制又是如何显现喃答案就是就是消息队列与事件循环。五、消息队列与事件循环工作线程将消息放在消息队列主线程通过事件循环过程去取消息。消息队列消息队列是一个先进先出的队列它里面存放着各种消息。事件循环事件循环是指主线程重复从消息队列中取消息、执行的过程。1. 事件循环(eventloop)主线程不断的从消息队列中取消息执行消息这个过程称为事件循环这种机制叫事件循环机制取一次消息并执行的过程叫一次循环。大致实现过程如下while(true) { var message queue.get() execute(message)}例如$.ajax({ url: xxxx, success: function(result) { console.log(1) }})setTimeout(function() { console.log(2)}, 100)setTimeout(function() { console.log(3)})console.log(4)// output4321 或 4312其中主线程// 主线程console.log(4)异步队列// 异步队列function () { console.log(3)}function () { // 100ms后 console.log(2)}function() { // ajax加载完成之后 console.log(1)}事件循环是JavaScript实现异步的具体解决方案其中同步代码直接执行异步函数先放在异步队列中待同步函数执行完毕后轮询执行 异步队列 的回调函数。2. 消息队列其中消息就是注册异步任务时添加的回调函数。$.ajax(XXX, function(res) { console.log(res)})...主线程在发起 AJAX 请求后会继续执行其他代码AJAX 线程负责请求 XXX拿到请求后会封装成 JavaScript 对象然后构造一条消息// 消息队列里的消息var message function () { callback(response)}其中 callback 是 AJAX 网络请求成功响应时的回调函数。主线程在执行完当前循环中的所有代码后就会到消息队列取出这条消息(也就是 message 函数)并执行它。到此为止就完成了工作线程对主线程的 通知 回调函数也就得到了执行。如果一开始主线程就没有提供回调函数AJAX 线程在收到 HTTP 响应后也就没必要通知主线程从而也没必要往消息队列放消息。异步过程中的回调函数一定不在当前这一轮事件循环中执行。六、异步与事件消息队列中的每条消息实际上都对应着一个事件。其中一个重要的异步过程就是DOM事件 var button document.getElementById(button)button.addEventLister(click, function(e) { console.log(事件)})从异步的角度看addEventLister 函数就是异步过程的发起函数事件监听器函数就是异步过程的回调函数。事件触发时表示异步任务完成会将事件监听器函数封装成一条消息放在消息队列中等待主线程执行。事件的概念实际上并不是必须的事件机制实际上就是异步过程的通知机制。另外所有的异步过程也都可以用事件来描述。例如setTimeout(func, 1000)// 可以看成timer.addEventLister(timeout, 1000, func)其中关于事件的详细描述可以看这篇文章事件绑定、事件监听、事件委托这里不再深入介绍。七、生产者与消费者生产者和消费者问题是线程模型中的经典问题生产者和消费者在同一时间段内共用同一个存储空间生产者往存储空间中添加数据消费者从存储空间中取走数据当存储空间为空时消费者阻塞当存储空间满时生产者阻塞。从生产者与消费者的角度看异步过程是这样的工作线程是生产者主线程是消费者(只有一个消费者)。工作线程执行异步任务执行完成后把对应的回调函数封装成一条消息放到消息队列中主线程不断地从消息队列中取消息并执行当消息队列空时主线程阻塞直到消息队列再次非空。那么异步的实现方式有哪些喃ES6之前callback、eventloop、PromiseES6GeneratorES7:Async/Await八、走在最后1. ❤️玩得开心不断学习并始终保持编程。?2. ?点击原文查看更多精彩文章?3. 如有任何问题或更独特的见解欢迎联系瓶子君(扫码关注公众号回复 123 即可)??我知道你 “在看”