簡體   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