JavaScript中异步编程的工作模式 --- 同步模式/异步模式||异步的EventLoop消息队列

Posted 萌萌的DDD

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中异步编程的工作模式 --- 同步模式/异步模式||异步的EventLoop消息队列相关的知识,希望对你有一定的参考价值。

Part01 --- 概述

javascript是以单线程为主的工作模式

采用单线程工作的原因

        最早JavaScript在设计的初衷是在浏览器中解决交互问题的脚本语言,以操作浏览器dom元素为主。

        如果同时在浏览器中添加一条dom,并且在下一行代码中删除了一条dom,在多线程的环境下浏览器并不能确认具体以那一条代码为基准进行执行。因此,将JavaScrtpt设计为单线程,也就是逐行执行。

        这样的优势也就是更安全,并且因为逐行执行也更简单便于阅读。

        但是弊端也很明显,如果有一条非常耗时的操作,他会阻塞代码执行,直到操作结束,因此下面的代码必须等待耗时操作结束,因此对性能会有较大的影响。

所以JavaScript为了解决耗时任务的执行,将执行模式分成了两种:同步模式/异步模式


Part 02 --- 同步模式

同步模式(SyncHronous)

        同步模式指的就是我们代码当中的任务依次执行,后一个任务也就必须等待前一个代码接受才能开始执行。

        程序的执行顺序与我们代码的编写顺序是完全一致的。

举例同步模式执行:

console.log('global begin');

function bar() {
    console.log('bar task');
}

function foo() {
    console.log('foo task');
    bar()
}

foo()

console.log('global end');

调用栈顺序

call stack

(anonymous) // 匿名调用  可以理解为将所有的代码压入一个匿名函数中进行调用

console.log('global begin'); // 压入调用栈  调用结束释放

foo()  // 压入调用栈

console.log('foo task'); // 调用 foo函数中的console.log   调用结束释放

bar()   //  将foo函数中的bar函数压入调用栈

console.log('bar task'); // 调用 bar函数中的console.log  调用结束释放

// 结束 bar 调用

// 结束 foo 调用


console.log('global end'); // 压入调用栈  调用结束释放

// 代码结束执行

 


Part 03 --- 异步模式

异步模式(AsyncHronous)

        异步模式的api,不会等待这个任务的结束,才开始下一个任务。

        对于耗时的任务,他都是开启过后立即往后执行下一个任务。

        后续逻辑一般会通过回调函数的方式去定义。

如果没有异步模式,单线程的JavaScript就无法同时处理大量的耗时任务。

举例异步模式执行:

console.log('global begin');

setTimeout(function time1() {
    console.log('time1 invoke');
}, 1800)

setTimeout(function time2() {
    console.log('time2 invoke');
    setTimeout(() => {
        console.log('inner invoke');
    }, 1000);
}, 1000)

console.log('golbal end');

Call stack

console.log('global begin');  // 压栈 释放

time1 .//  异步模式  调用挂起

time2  //  异步模式  调用挂起

console.log('golbal end');  //  压栈  释放

console.log('time2 invoke'); // time2调用 

inner //  异步模式 调用挂起

//time2 调用结束释放

console.log('time2 invoke'); // time1调用   

// time1 调用结束 释放

console.log('inner invoke');  // inner 调用

// inner 调用结束 释放

Web APIs

time1  1.8s

time2 1s

inner 1s

Event loop

time2  // 倒计时先结束 进入事件队列 排队  再放入调用栈 

time1 //  倒计时结束  进入队列排队

inner //  倒计时结束 进入队列排队

        直到消息队列EventLoop和调用栈 都执行结束了,那么代码才会释放调用栈中的匿名函数

        如果,我们把调用栈看作为执行的工作表,那么我们可以把EventLoop可以称之为代办的工作表。当调用栈执行结束后才会依次执行消息队列中的调用

        整个过程中可以不断地向消息队列中放入任务,那这些任务中会根据在异步结束后的顺序,在消息队列中进行排队等待执行。

 


Part 04 --- 回调函数

回调函数(call back)

所有异步编程方案的根基

// 定义异步函数
function foo(callback) {
    setTimeout(() => {
        callback()
    }, 3000);
}

// 执行异步函数
foo(function() {
    console.log(('这就是一个回调函数'));
    console.log(('调用者定义这个函数,执行者执行这个函数'));
    console.log(('其实就是调用者告诉异步任务结束后应该做什么'));
})

由调用者定义,交给执行者执行的函数称之为回调函数。

以上是关于JavaScript中异步编程的工作模式 --- 同步模式/异步模式||异步的EventLoop消息队列的主要内容,如果未能解决你的问题,请参考以下文章

读书——javascript异步编程

异步编程工作过程

JavaScript异步编程

在现代 JavaScript 中编写异步任务

javascript 异步编程

异步工作流控制-condCall