JavaScript执行机制 — 事件循环

JS执行机制

  • 单线程
  • 异步
  • 事件循环

单线程

总所周知,JavaScript是一门单线程语言!

JS作为一种脚本语言,多被用于浏览器中进行Web开发,它的主要用途是通过操作DOM,BOM等达到与用户进行交互的目的。这也就意味着它只能是单线程的,以此来避免多个线程对同一DOM元素进行冲突的操作。

虽然H5出了一个新特性WebWorker为JS创造多线程环境,但多用来计算密集型或高延迟的任务,让主线程流程不被阻塞。但WebWorker也有诸多限制,同源限制,DOM限制,通信限制,脚本限制及文件限制等,这里不多做叙述。

异步

如果JS在执行一行代码时,解析时间过长,例如:大量数据的循环遍历等,那么后面的代码将会被阻塞,暂时无法执行,对用户而言,页面就卡住了,没办法进行迅速有效的交互,此时就需要JS进行异步操作!

异步的实现,也就是JS的执行机制 — 事件循环(event loop)

事件循环

因为JS是单线程的,所以所有的任务都是需要排队的,这里将JS的任务分为两种:

  • 同步任务(synchronous):在主线程上排队执行的任务
  • 异步任务(asynchronous):不进入主线程,而是进入“任务队列”(task queue)的任务

任务队列也是事件队形,运行机制大致如下:

  • 同步任务在主线程上执行,形成一个执行栈(先进先出)
  • 当执行栈执行完所有同步任务后,主线程将从“任务队列”中读取事件,执行异步任务

异步任务又细分为:

  • 宏观任务:宏观即指宿主,也是就是写代码的人发起的任务(整体代码script,setTimeout,setInterval)
  • 微观任务:微观即指JS,由JS引擎发起的任务(Promise.then是Promise的回调函数,process.nextTick)

完整的事件循环:

  1. 第一轮循环将整体JS当作一个宏任务来运行,主线程判断任务类型,同步任务逐步执行,当遇到异步任务将其推入事件队列(宏任务推入宏任务队列,微任务推入当前宏任务的微任务队列)
  2. 主线程执行完一轮轮同步(宏)任务后,依次执行当前的所有微任务
  3. 执行完当前所有任务,结束第一轮循环,开始第二轮循环
  4. 执行同步(宏)任务,将微任务推入当前的宏任务的微任务队列
  5. 开始循环往复

示例1:

console.log('1')
setTimeout(function() {
    console.log('2')
    process.nextTick(function() {
        console.log('3')
    })
    new Promise(function(resolve) {
        console.log('4')
        resolve()
    }).then(function() {
        console.log('5')
    })
})

process.nextTick(function() {
    console.log('6')
})

new Promise(function(resolve) {
    console.log('7')
    resolve()
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9')
    process.nextTick(function() {
        console.log('10')
    })
    new Promise(function(resolve) {
        console.log('11')
        resolve()
    }).then(function() {
        console.log('12')
    })
})

示例2:

async function testSometing() {
    console.log("执行testSometing");
    return "testSometing";
}

async function testAsync() {
    console.log("执行testAsync");
    return Promise.resolve("hello async");
}

async function test() {
    console.log("test start...");
    const v1 = await testSometing();
    console.log(v1);
    const v2 = await testAsync();
    console.log(v2);
    console.log(v1, v2);
}

test();

var promise = new Promise((resolve) => {
    console.log("promise start..");
    resolve("promise");
});
promise.then((val) => console.log(val));
setTimeout(()=>{console.log("setTime1")},3000);
console.log("test end...")

你可能感兴趣的:(JS)