建设审批网站查询,清智优化北京,朱能源做网站,网页设计目的怎么写文章简介
本文为【JavaScript 漫游】专栏的第 017 篇文章#xff0c;主要记录了 ES5 规范中异步操作的基本知识点。
单线程模型同步任务和异步任务任务队列和事件循环异步操作的模式
单线程模型
单线程模型指的是#xff0c;JS 只在一个线程上运行。它同时只能执行一个任… 文章简介
本文为【JavaScript 漫游】专栏的第 017 篇文章主要记录了 ES5 规范中异步操作的基本知识点。
单线程模型同步任务和异步任务任务队列和事件循环异步操作的模式
单线程模型
单线程模型指的是JS 只在一个线程上运行。它同时只能执行一个任务其他任务都必须在后面排队等待。
JS 之所以采用单线程模型是不想让浏览器变得太复杂。多线程需要共享资源、且有可能修改彼此的运行结果对于一种网页脚本语言来说过于复杂。
采用该模型的好处是实现起来比较简单执行环境相对单纯。而坏处是只要有一个任务耗时很长后面的任务都必须排队等着会拖延整个程序的执行。
常见的浏览器无响应往往就是因为某一段 JS 代码长时间运行导致整个页面卡在这个地方其他任务无法执行。JS 语言本身并不慢慢的是读写外部数据比如等待 Ajax 请求返回结果。这个时候如果对方服务器迟迟没有响应或者网络不畅通就会导致脚本的长时间停滞。
JS 采用了事件循环机制来解决上述问题。如果想要利用多核 CPU 的计算能力HTML5 提出了 Web Worker 标准允许 JS 脚本创建多个线程分为主线程和其他子线程子线程完全受主线程控制且不得操作DOM。
总的来说单线程模型虽然对 JS 构成了很大的限制但也因此使它具备了其他语言不具备的优势。如果用得好JS 程序是不会出现堵塞的。
同步任务与异步任务
程序里面所有的任务可以分成两类同步任务synchronous 和异步任务 asynchronous。
同步任务是那些没有被引擎挂起、在主线程上排队执行的任务。只有前一个任务执行完毕才能执行后一个任务。
异步任务是那些被引擎放在一边不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了比如 Ajax 操作从服务器得到了结果该任务采用回调函数的形式才会进入主线程执行。排在异步任务后面的代码不用等待异步任务结束会马上运行也就是说异步任务不具有堵塞效应。
举例来说Ajax 操作可以当作同步任务处理也可以当作异步任务处理由开发者决定。如果是同步任务主线程就等着 Ajax 操作返回结果再往下执行如果是异步任务主线程在发出 Ajax 请求以后就直接往下执行等到 Ajax 操作有了结果主线程再执行对应的回调函数。
任务队列和事件循环
JS 运行时除了一个正在运行的主线程引擎还提供了一个任务队列task queue里面是各种需要当前程序处理的异步任务。实际上根据异步任务的类型存在多个任务队列。为了方便理解这里假设只存在一个队列。
首先主线程会去执行所有的同步任务。等到同步任务全部执行完就会去看任务队列里面的异步任务。如果满足条件那么异步任务就重新进入主线程开始执行这时它就变成同步任务了。等到执行完下一个异步任务再进入主线程开始执行。一旦任务队列清空程序就结束执行。
异步任务的写法通常是回调函数。一旦异步任务重新进入主线程就会执行对应的回调函数。如果一个异步任务没有回调函数就不会进入任务队列也就是说不会重新进入主线程因为没有用回调函数指定下一步的操作。
JavaScript 引擎怎么知道异步任务有没有结果能不能进入主线程呢答案就是引擎在不停地检查一遍又一遍只要同步任务执行完了引擎就会去检查那些挂起来的异步任务是不是可以进入主线程了。这种循环检查的机制就叫做事件循环Event Loop。
异步操作的模式
回调函数
回调函数是异步操作最基本的方法。
下面是两个函数 f1 和 f2编程的意图是 f2 必须等到 f1 执行完成才能执行。
function f1(callback) {// ...callback();
}function f2() {// ...
};f1(f2);回调函数的优点是简单、容易理解和实现缺点是不利于代码的阅读和维护各个部分之间高度耦合使得程序结构混乱、流程难以追踪尤其是多个回调函数嵌套的情况而且每个任务只能指定一个回调函数。
事件监听
另一种思路是采用事件驱动模式。异步任务的执行不取决于代码的顺序而取决于某个事件是否发生。
还是以 f1 和 f2 为例。首先为 f1 绑定一个事件这里采用的是 jQuery 的写法。
f1.on(done, f2);当 f1 发生 done 事件就执行 f2。然后对 f1 进行改写
function f1(){setTimeout(function() {// ...f1.trigger(done);}, 1000);
};f1.trigger(done) 表示执行完成后立即触发 done 事件从而开始执行 f2。
这种方法的优点是比较容易理解可以绑定多个事件每个事件可以指定多个回调函数而且可以去耦合decoupling有利于实现模块化。缺点是整个程序都要变成事件驱动型运行流程会变得很不清晰。阅读代码的时候很难看出主流程。
发布/订阅
事件完全可以理解成信号如果存在一个信号中心某个任务执行完成就向信号中心发布一个信号其他任务可以向信号中心订阅这个信号从而知道什么时候自己可以开始执行。这就叫做发布/订阅模式publish-subscribe pattern又叫观察者模式observer pattern。
这个模式有多种实现具体的实现可以在使用 vue 或 react 技术栈的时候再进行研究这里不作记录。