单线程的模式javascript
概述
最早的javascript是一门运行在浏览器端的脚本语言, 目的是为了实现页面的动态交互, 而实现页面交互的核心是操作dom元素, 为了防止出现复杂的线程同步问题, javascript采用了单线程模式工作
javascript单线程的工作模式是指,在javascript运行环境中始终负责执行代码的线程始终只有一个.即每次只能一个任务,多个任务排队执行,依次完成所有任务. 这种模式的优点是更安全、更简单. 缺点也同样明显,当我们遇到一个耗时任务时, 后面的任务就会等待该任务的结束, 整个程序就会拖延、假死. 为了解决耗时任务阻塞执行的问题,javascript将任务任务执行的模式分为: 同步模式(Synchronous) 和 异步模式(Asynchronous)两种
两种模式
同步模式
代码中的任务依次执行, 后一个任务必须等待前一个任务结束后开始执行, 任务执行的顺序与代码编码顺序一致.单线程模式下大多数任务以同步模式执行. 阻塞: 某一任务执行时间过长,导致后面任务执行延迟.
console.log('global begin')
function bar () {
console.log('bar task')
}
function foo () {
console.log('foo task') bar()
}
foo()
console.log('global end')
异步模式
不会等待上一个任务结束才执行打一个任务, 对于耗时操作,一般开启过后立即执行下一个任务, 耗时任务的后续逻辑一般通过回调函数的方式定义, 在内部耗时操作执行完成之后, 自动执行回调函数. 异步操作使单线程的javascript能够同时处理大量耗时任务, 但是异步会带来代码执行顺序混乱的问题.
console.log('global begin')
setTimeout(function timer1 () {
console.log('timer1 invoke')
}, 1800)
setTimeout(function timer2 () {
console.log('timer2 invoke')
setTimeout(function inner () {
console.log('inner invoke')
}, 1000)
}, 1000)
console.log('global end')
注意:javasctipt是单线程的, 浏览器并不是单线程的. 我们这里讲的同步和异步是指运行环境提供的API是以同步或异步的方式进行工作的.
事件循环
js 先执行同步任务, 同步任务执行完成再执行异步队列中的异步任务, 这样不断重复的过程,就叫做事件循环(Event loop)
在异步线程中,任务队列起到了十分重要的作用, 任务队列是一个存储着待执行任务的队列,其中的任务严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行。任务队列每次仅执行一个任务,在该任务执行完毕之后,再执行下一个任务,一个任务开始后直至结束,不会被其他任务中断。
关于宏任务和微任务
JavaScript单线程中的任务可以细分为宏任务和微任务。每个宏任务结束后, 都要清空所有的微任务
宏任务是由宿主发起的,微任务是JS自身发起。
ES5之后,JS引入了Promise,这样,不需要浏览器,JS殷勤自身也能够发起异步任务了。
宏任务:script( 整体代码),setTimeout,setInterval,UI交互事件
微任务:promise,nextTick
js 事件执行顺序
- 同步 > 异步
- 微任务 > 宏任务
即:
- 微任务:
Promise,process.nextTick。 - 宏任务:
整体代码script,setTimeout,setInterval
代码测试1:
// 代码
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 执行结果
script start
async1 start
async2
script end
async1 end
代码测试2:
// 代码
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
// 执行结果
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout