js是一门单线程语言,所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。如果一个任务耗时过长,那么后面的任务就必须一直等待下去,会拖延整个程序,常见浏览器无反应,可能就是一段代码死循环,造成程序卡住在这个位置,无法继续。而js之所以会是单线程语言的原因和它的用途有很大的关系,我们都知道,JavaScript作为浏览器的脚本语言,主要用来实现与用户的交互,利用JavaScript,我们可以实现对DOM的各种各样的操作,如果JavaScript是多线程的话,一个线程在一个DOM节点中增加内容,另一个线程要删除这个DOM节点,那么这个DOM节点究竟是要增加内容还是删除呢?这会带来很复杂的同步问题,因此,JavaScript是单线程的。 所以为了解决这个问题,js的任务执行模式分为两种:同步和异步。
"同步任务"就是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务 例:
// 同步代码 function fun1() { console.log(1); } function fun2() { console.log(2); } fun1(); fun2(); // 输出 //1 //2很容易可以看出,输出会依次输入1,2,因为代码是从上到下依次执行,执行完fun1(),才继续执行fun2()。
"异步任务"是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务。 例:
function fun1() { console.log(1); } function fun2() { console.log(2); } function fun3() { console.log(3); } fun1(); setTimeout(function(){ fun2(); },0); fun3(); // 输出 //1 //3 //2因为setTimeout函数是异步的执行的,所以它之中的任务会等到满足执行条件时才会进入主线程,而不是一开始就在主线程之中,所以使用它可以控制js的执行顺序。
(1)所有同步任务都在主线程上执行,行成一个执行栈。 (2)主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件。 (3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 (4)主线程不断的重复上面的第三步。
实现异步模式的方法有很多,比较常用的有: (1)延迟类:setTimeout、setInterval、requestAnimationFrame、setImmediate。 (2)监听事件实现的类型:监听new Image加载状态、监听script加载状态、监听iframe加载状态、Message。 (3)带有异步功能类型 Promise、ajax等等。
