Javascript 默认是同步(阻塞)还是异步(非阻塞)

Posted

技术标签:

【中文标题】Javascript 默认是同步(阻塞)还是异步(非阻塞)【英文标题】:Is Javascript synchronous(blocking) or Asynchronous(nonblocking) by default 【发布时间】:2013-05-07 14:15:45 【问题描述】:

我正在尝试掌握 javascript 异步函数和回调。

我陷入了回调函数的概念,我正在阅读一些地方:它们用于顺序执行代码(主要在 jquery 的上下文中,例如动画)和一些地方特别是在 Nodejs 的上下文中;它们用于并行执行异步并避免代码阻塞。

那么,该主题的专家能否阐明这一点并清除我心中的这个模糊问题(示例??)。 所以我可以考虑使用回调函数

或者这完全取决于您在代码中调用/放置回调函数的位置? .

谢谢,

P.S:我担心这个问题会很主观,但我仍然可以期待具体的答案(也许是一些例子)

编辑:实际上这是来自互联网的例子,这让我模棱两可:

function do_a()
  // simulate a time consuming function
  setTimeout( function()
    console.log( '`do_a`: this takes longer than `do_b`' );
  , 1000 );


function do_b()
  console.log( '`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`' );


do_a();
do_b();

结果

`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`
`do_a`: this takes longer than `do_b`

根据我的理解,当 JS 是顺序的时,do_b 应该总是在 do_a 之后。

【问题讨论】:

JavaScript 是 JavaScript;它取决于上下文、用法、引擎等。 您能否提供一些您不确定是阻塞还是非阻塞的示例代码? JavaScript 通常是同步的,但 setTimeout 根据定义是异步的。这是一个很好的入门:developer.mozilla.org/en-US/docs/DOM/window.setTimeout 【参考方案1】:

在节点长时间运行的进程中,使用process.nextTick() 将函数/回调排队。这通常在节点的 API 中完成,除非您的编程(在 api 之外)使用阻塞的东西或长时间运行的代码,否则它不会对您产生太大影响。下面的链接应该能更好地解释它。

howtonode process.nextTick()

jQuery AJAX 也接受回调,例如它的编码在继续下一个代码块之前不等待服务器响应。它只是记住服务器响应时要运行的函数。这是基于浏览器公开的 XMLHTTPRequest 对象。 XHR 对象会记住响应返回时要回调的函数。

setTimeout(fn, 0) 的 javascript 将在调用堆栈为空时运行一个函数(下一个可用的空闲刻度),该函数可用于创建类似异步的功能。setTimeout(fn, 0) question on ***

总结 javascript 的异步能力与它们编程的环境和 javascript 本身一样重要。除非您使用一些 API/脚本,否则仅使用大量函数调用和回调不会获得任何魔力。

Jquery Deferred Object 是另一个很好的 jQuery 异步功能链接。谷歌搜索可能会为您找到有关 jQuery Deferred 如何工作的信息,以获得更多洞察力。

【讨论】:

【参考方案2】:

JavaScript 的核心在很大程度上是同步的,因为函数在完成之前完全完成它们的任务。在 AJAX 出现之前,实际上只有 setTimeout 和 setInterval 提供了异步行为。

但是,很容易忘记事件处理程序实际上是异步代码。附加处理程序不会调用处理程序代码,并且直到将来某个不可知的时间才会执行该代码。

然后是 AJAX,它调用服务器。这些调用可以配置为同步的,但开发人员通常更喜欢异步调用并使用回调方法来实现它们。

然后,我们看到了 JS 库和工具包的激增。这些努力使不同浏览器的事物实现同质化,并建立在异步代码的回调方法之上。您还开始看到更多用于数组迭代或 CSS 查询结果处理之类的同步回调。

现在,我们看到了 Deferred 和 Promise 的混合。这些对象代表长时间运行的操作的值,并提供一个 API 用于在该值到达时处理该值。

NodeJS 倾向于异步处理许多事情;这是真的。然而,这更多是他们的设计决定,而不是 JS 的任何固有异步性质。

【讨论】:

【参考方案3】:

Javascript 始终是一种同步(阻塞)单线程语言,但我们可以通过编程使 Javascript 行为异步。

同步码:

console.log('a');
console.log('b');

异步代码:

console.log('a');
setTimeout(function() 
    console.log('b');
, 1000);
setTimeout(function() 
    console.log('c');
, 1000);
setTimeout(function() 
    console.log('d');
, 1000);
console.log('e');

这输出:a e b c d

【讨论】:

在这种情况下阻塞是什么意思? @SandeepanNath 你可能已经明白了,但是对于未来的访问者:阻塞是指串行处理。一次只做一件事。另一方面,非阻塞代码(异步)可以并行(或多线程)运行。优点是可以更快。

以上是关于Javascript 默认是同步(阻塞)还是异步(非阻塞)的主要内容,如果未能解决你的问题,请参考以下文章

libevent到底是同步还是异步,是阻塞还是非阻塞

libevent到底是同步还是异步,是阻塞还是非阻塞

好好聊聊同步异步阻塞非阻塞

同步异步阻塞和非阻塞

阻塞,非阻塞, 同步,异步

单线程 异步 同步 阻塞 非阻塞