繁体   English   中英

javascript 中的异步行为和回调

[英]Asynchronous behavior and callbacks in javascript

我在各种网站上跳来跳去,但无法理解回调如何使 javascript 异步。 据我所知,回调是在另一个函数内部调用的任何函数。 这只是另一个函数调用。 javascript 如何知道异步执行哪些函数以及它如何在后台处理?

示例代码 1

function A(x){
//...code for func A;
}

function B(y){
//...code for func B;
A(2);  // 2 for example
}

示例代码 2:

function A(x){
//...code for func A;
}

function B(y,A){
//...code for func B;
A(2);  // 2 for example
}

请解释javascript如何区分这两个代码?

我在各种网站上跳来跳去,但无法理解回调如何使 javascript 异步。

他们不。 您发布的代码本身不是异步的。 回调本身不是异步模式(例如查看Array.prototype.forEach ),但它们被用作处理异步行为的一种方式。

据我所知,回调是在另一个函数内部调用的任何函数。 这只是另一个函数调用。

基本上,除了它们也作为参数传递。 当我们在 javascript 中说回调时,我们通常指的是从一个函数传递到另一个函数并回调初始函数的函数,因此得名。 然而,一般来说,回调只是一段可执行代码,它作为参数传递给其他代码。


您在此处提供的两个示例之间的主要区别在于它们如何获取彼此的访问权限,而不是它们是异步的还是同步的。

两个示例都包含同步代码,但其中只有一个包含回调:

  • 示例 1:函数 B 通过其全局作用域获得对 A 的访问。 不回调
  • 示例 2:函数 B 通过其参数获取对 A 的访问权:回调

对于示例 1,无论您如何调用B(y) ,由于它始终A内部调用A ,因此它不会回调任何内容,它只会调用另一个函数。

对于示例 2,您可以使用另一个function C(){}调用B(y, A)B(y, C) ,它会回调您传递给它的任何函数。

如果您像这样重命名函数,也许就不那么令人困惑了:

示例代码 1

function A(x){
  //...code for func A;
}

function B(y){
  //...code for func B;
  A(2);  // calls above A()
}

示例代码 2:

function A(x){
  //...code for func A;
}

function B(y, callback){
  //...code for func B;
  callback(2);  // calls whichever callback you pass in
}

演示示例

 // EXAMPLE 1 function A1() { console.log('A1 is called'); } function B1() { console.log('B1 is called'); A1(2); // calls above A() } B1(); // Output: // B1 is called // A1 is called B1('whatever'); // Output: // B1 is called // A1 is called // EXAMPLE 2 function A2() { console.log('A2 is called'); } function B2(callback) { console.log('B2 is called'); callback(); // calls whichever callback you pass in } // We can callback to any function (but not no function) B2(A1); // Output: // B2 is called // A1 is called B2(A2); // Output: // B2 is called // A2 is called B2(); // Output: // B2 is called // Uncaught TypeError: callback is not a function (because we didn't pass anything as the callback)

示例代码 1 作为异步

现在让我们使用常用工具setTimeout函数演示一些异步行为。 我将使用示例代码 1,因为它不包含任何回调代码,以展示回调如何与异步行为相关联。

function A(x){
  //...code for func A;
}

function B(y){
  //...code for func B;
  setTimeout(A, 3000); // call A after 3 seconds
}

B();

在上面的代码中,函数A作为回调传递给函数setTimeout 这意味着setTimeout定义在概念上看起来像:

function setTimeout(callback, duration) {
 // call callback after duration milliseconds
}

执行上述代码时会发生什么,词法解析器首先将函数提升到代码的顶部 然后调用B() ,然后是所有同步代码后记,因为 JS 是单线程的。 这意味着在调用setTimeout()的线程终止之前不能执行A

只有当所有同步代码都完成并且 3 秒过去了,你才会调用A()

通常,无论何时您编写一些代码以在接收到来自服务器的数据或用户单击鼠标时做出反应,该代码都是异步的。 它在发生某些事情时被执行。

正如@Pointy在评论中指出的那样,这种异步行为本身并不是 JavaScript 的直接特性。 它通常来自与运行 JS 的系统的交互以及系统发送的事件(用户与浏览器交互或操作系统与 NodeJS 之类的交互)

Javascript 的异步行为

 <script> var message = ''; function writeToDocument( string ) { window.message += '<br/>'+string; document.write(window.message); } function A() { var string = 'A is Called'; setTimeout( function(){writeToDocument(string)},3000); } function B() { writeToDocument('B is Called'); } A(); //We are calling A first; B(); </script>

输出

B is Called
A is Called

即使我们先调用了 A,也先调用了 B,但Javascript 是异步的

PHP 的同步行为

<?php

function writeToDocument( $string )
{
    echo '<br/>'.$string; 
}

function A()
{
    sleep(3000);
    writeToDocument('A is Called');
}

function B()
{
    writeToDocument('B is Called');
}

A();
B();

输出

A is Called
B is Called

除非 A 执行完毕,否则不会调用 B, PHP 是同步的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM