同步编程与异步编程

2020-09-12 16:45:09

在本文中,我们将讨论什么是同步编程?什么是异步编程?JavaScript是同步的还是异步的?

许多开发人员很难理解回调、承诺和异步/等待等主题,其中一个原因可能是不理解它们背后的实际需求和核心逻辑。

借助一个例子可以更好地解释这一点。假设你给你的朋友布置了一组任务:

你的朋友现在所做的是,他首先完成任务一,然后前往邻近的城镇,假设这需要x个时间。然后他回到你身边,给你电子游戏,然后去执行第二个任务,假设这需要y个时间。总时间是x+y。这只是几个任务,但假设有数百个任务,如果他是一个人按照给定的顺序逐个完成所有任务,那么总时间会迅速增加。

上面讨论的场景是JavaScript默认情况下运行其代码的方式,它逐行执行每个任务,然后再继续执行另一个任务,这意味着对于要运行的代码中的最后一个任务或命令,应该首先执行它上面的所有代码。JavaScript的代码在单个线程中执行,如果一个函数需要一些时间才能完成,它将在此期间冻结其他所有内容。一次执行一件事完全是同步的。

默认情况下,JavaScript是一种同步的、阻塞的单线程语言。这仅仅意味着一次只有一个操作在进行。Windows警报功能就是一个很好的例子,当执行此功能时,ALERT(Hello World)就是一个很好的例子,整个网页都会被卡住,除非您解除警报,否则无法与其交互。

始终同步也可能是有害的,正如上面示例中所讨论的,如果有很多耗时的代码行,您的应用程序将变得慢得多。同步IO调用会阻塞整个线程,并且JavaScript是单线程的。让我们看看这意味着什么。

正如您在Result End中看到的,直到循环执行完毕才会记录在控制台中,这是一个相当小的循环,想象一下如果它是I<;2000而不是20,您可以看到它会变得多么耗时。当您在具有大量服务器请求的大型应用程序上工作时,这会成为一个非常严重的问题。

那么,它应该如何解决,答案是异步编程模型,这意味着您可以一次执行多个任务,而不必等待当前任务完成后再继续执行下一个任务。可以对JavaScript进行操作,使其以异步方式运行,这就是在上面的代码行中默认使用JavaScript的原因。

这就是异步/等待、承诺和回调发挥作用的地方,默认情况下,它们用于将JavaScript代码同步到异步。

让我们先多了解一下异步模型,在上面的示例中,假设您现在有两个朋友来执行相同的任务。所以,现在这两个任务同时执行,这导致了x所用的总时间(这应该是两个任务中最长的一个)。当你有更多的朋友帮助你时,生活就会变得容易得多,只做两项任务似乎不会节省多少时间,但同样可以完成数百项任务。

因此,简而言之,JavaScript刚刚变成了多线程,能够同时执行多个任务。这将我们的定义更改为JavaScript是一种异步、非阻塞、多线程的语言。

请稍等片刻,那么有两个定义,哪一个是正确的?*答案是JavaScript是这两个定义的一部分。

众所周知,JavaScript代码由V8、SpiderMonkey、Rhino、KJS、Chakra等JavaScript引擎执行。所有这些引擎都有负责在后台处理异步代码的WebAPI。调用堆栈识别Web API的异步/等待、setTimeout()等函数,并将它们传递给浏览器进行处理。一旦浏览器完成了这些任务,它们就会返回并作为回调被推送到堆栈上。

演示这一点的最佳方式是使用setTimeout()来延迟函数的执行,第一个参数是函数(称为回调函数),另一个参数是以毫秒为单位的时间。

Console.log(";start";)是堆栈上的第一个,因此它会被记录。接下来,JavaScript引擎注意到不是由JavaScript处理的setTimeout(),并将其发送到Web API进行异步处理。

调用堆栈继续前进,而不关心传递给WebAPI的代码,并打印console.log(";end";)。

SetTimeout()函数使中间操作在一段延迟(1秒)之后发生,从而使操作异步。整个操作不会暂停1秒,以便可以记录中间,而是继续执行下一个任务,记录结束。

即使时间间隔更改为0秒,它仍将由Web API处理,并在结束后记录。

这种跳过要在后台处理的异步代码块并前进到下一行代码而不阻塞代码执行的方式使JavaScript成为非阻塞的。

在本文中,您了解了编程的同步和异步模型,现在您了解了异步/等待、承诺和异步回调的需要和使用。