1. 程式人生 > >js與ajax中非同步呼叫的簡單理解

js與ajax中非同步呼叫的簡單理解

這個兩段程式碼是在同一個js檔案中

function connectServer(callback) {
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
    } else return;
    xmlhttp.onreadystatechange = function() {
        if
(xmlhttp.readyState == 4 && xmlhttp.status == 200) { callback(xmlhttp.responseText); } } // 這裡是非同步呼叫的模式 // 這裡的server是用node啟動的服務端指令碼,返回一個隨機數 xmlhttp.open('GET', '../server', true); xmlhttp.send(); }

下面這裡是為一個button觸發Click時間時請求一個隨機數並寫入內部的元素內容中

        buttons[i].onclick = function
(i) {
return function() { if (this.disabled) {return}; bannedButtons(this, buttons); this.childNodes[1].innerHTML = '...'; this.childNodes[1].style.visibility = 'visible'; connectServer(function(data) { buttons[i].childNodes[1
].innerHTML = data; bannedButtons(null, buttons); enableButtons(buttons); checkInfoIsReady(buttons); }); } }(i);

為什麼connectServer(function(data) {….}會是非同步呼叫呢
先看些其他的

      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function() {
          return function () {
              console.log(i);
           }
        };
      }

這種形式是事件觸發的時候是 return內層函式 而不是我們想要的記憶體函式的執行結果

      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function() {
          console.log(i);
        }(i);
      }

上面的程式碼會在控制檯輸出0,1,2,3,4,五 行
這是因為function(){}(i)這樣子寫就相當於直接運行了這個函式 不用等事件觸發

      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function(i) {
          console.log(i);
        }(i);
      }
      或
      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function(x) {
          console.log(x);
        }(i);
      }

發現結果同上 可以發現是i引數覆蓋事件引數x變成i, 但是依舊不是事件觸發的時候才執行

      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function() {
          return function() {
                console.log(i);
          }
        }(i);
      }

理解js的垃圾回收機制對閉包有很大幫助, 記住一點js不會回收需要用到的東西 而閉包正式要使用大外部變數的東西,所以如果外部的變數沒有被回收 那麼你才有可能訪問到你需要的值
這樣子寫閉包是不對的因為那個console中的i不是(i)因為根本就沒有產生關係,是因為記憶體函式根本就沒有接收到你傳的引數i,所以console的i會自動向上層查詢i變數,因為是事件觸發非同步的所以此時的i都是5 正確的寫應該是這樣子的 如下

      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function(i) {
          return function() {
                console.log(i);
          }
        }(i);
      }
或
      for (var i = 0; i < 5; i++) {
        buttons[i].onclick = function(x) {
          return function() {
                console.log(x);
          }
        }(i);
      }

這樣子寫就能保證i在往上尋找時,找到的是你用外部i賦給i變數的值

這裡那麼多的內容是幫助理解閉包的工作原理 只是加深對js的理解,從以上的例子可以看出, 這種事件觸發 並不是說直接最後執行,而是按照順序執行, 只是你不按閉包來寫 就感覺是最後才執行 其實依舊是順序的執行 只不過是非同步的觸發 注意閉包外層的那裡的(i)加上,如果沒有當你觸發的時候就是返回內層函式,而我們希望的是要執行內層函式,更進一步 你可以看到內層的x其實是新建的變數儲存i變數的值,並不是i變數 根據js垃圾回收機制,你能發現x是不會被回收的,也就是實際上有五個x變數
如果你不用閉包,那麼你就只能使用到最後一個i變數其值是5,這也就是常見的迴圈中放事件的結果不和你的料想一致的原因

接著 我們再來看 為什麼那裡的ajax為非同步的呼叫 首先明確一點在非同步模式中沒有return這種說法,並且都是採用回撥函式callback處理非同步 這兩點很關鍵 , 不注意這兩點 可能你就會掉到坑裡

function connectServer(callback) {
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
    } else return;
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            callback(xmlhttp.responseText);
        }
    }
        // 這裡是非同步呼叫的模式
        // 這裡的server是用node啟動的服務端指令碼,返回一個隨機數
    xmlhttp.open('GET', '../server', true);
    xmlhttp.send();
}
        buttons[i].onclick = function(i) {
            return function() {
                if (this.disabled) {return};
                bannedButtons(this, buttons);
                this.childNodes[1].innerHTML = '...';
                this.childNodes[1].style.visibility = 'visible';
                connectServer(function(data) {
                    buttons[i].childNodes[1].innerHTML = data;
                    bannedButtons(null, buttons);
                    enableButtons(buttons);
                    checkInfoIsReady(buttons);
                });
            }
        }(i);

分析如下
當用戶觸發button的點選事件時, 觸發connectServer ()函式的執行這裡首先是把一個匿名函式穿給callback這個引數,然後穿件一個XMLHttpRequest 物件,使用get方式非同步的向伺服器這裡即是server指令碼請求資料,接著這裡的onreadystatechange會仍入一個佇列(這個佇列是專門來對非同步程式儲存的) 當輪到非同步佇列進行時這個函式得到執行, 也就是說如果你的程式有一個普通的死迴圈程式, 那麼你不可能得到觸發的結果, 因為普通程式碼的處理總是在非同步佇列的前面, 當服務端處理完成請求ok且可以響應了 然後執行裡面的callback函式,剛才已經說了callback被函式賦值,而這裡的data資料得到的就是服務端返回的資料, 接著就是對這個資料進行處理了, 這樣就解決了非同步排程的問題,因為後面的程式碼是依賴服務端返回的資料的,剛好這種回撥函式的方法,解決了非同步的問題

綜上
再感悟下, 就是事件觸發處理非同步,也就是把利用垃圾回收機制,讓所需要的變數不被回收,或者覆蓋,從而實現,觸發的時候是你所期望的值

再感悟下, 就是回撥函式處理非同步,也就是把要處理的東西,帶到非同步佇列的感覺, 就是把要處理的東西,放到只有處理完才會進行的後面, 一般帶延遲的東西,都是會拋到非同步佇列的, 所以你的程式碼也要放在非同步中,防止再還沒來得及得到資料時,先行處理完了

相關推薦

jsajax中非同步呼叫簡單理解

這個兩段程式碼是在同一個js檔案中 function connectServer(callback) { if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest();

JS —— 筆記,$("document").ready() 中ajax $.ajax() 及同步非同步優先順序問題

jQuery 所有方法(包括 $.load()等)預設都是非同步執行的,所以,它們具有相同的執行順序優先順序。此時誰先執行取決於位置前後順序。 關鍵想記錄的一點是,若將某個這類AJAX 方法改為同步

$httpajax同步請求

在web前端開發中,雖然一般都是用的非同步網路請求解決大多數功能需求,但是在一些特定需求的情況下,我們還是要使用到同步的網路請求來解決一些特殊的需求。那麼本篇介紹的是實現AngularJS中$http與jQuery中ajax如何實現同步網路請求。 (一)$http同步網路請

【Java】構造器setter/getter區別的簡單理解

構造器 在類的例項化時,構造器的作用為**物件屬性的初始化** 初始化時,物件既可以是有參構造,也可以是無參構造 有參構造時,在建立物件時傳參 無參構造或是未明確寫明構造方法時,環境會預設呼叫 例如 /** * 無參構造 */ public cl

JSAjax實現非同步區域性重新整理的原理

function sendGet() { //開啟子執行緒的物件(需要考慮瀏覽器的相容性) var xmlhttp; if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行程式碼 xmlhttp=n

node.js使用async完成同步呼叫

node.js讓初學者最頭疼之處,莫過於徹頭徹尾的非同步機制。所有程式碼,在排版上的先後順序並不決定了其呼叫順序。然而人的思維恰恰是按照同步順序流轉的,於是令人叫苦不迭的情況應運而生——你理所當然的編寫了一段看似順序執行的程式碼,激動一run,哎喲我滴媽——null、顛倒的

講講JavaScript中非同步呼叫的發展

JS 中最基礎的非同步呼叫方式是 callback,它將回調函式 callback 傳給非同步 API,由瀏覽器或 Node 在非同步完成後,通知 JS 引擎呼叫 callback。對於簡單的非同步操作,用 callback 實現,是夠用的。但隨著負責互動頁面和 Node 出現,callback 方案的弊端

Unity3D中jsC#之間相互呼叫的解決辦法

轉載自:http://www.manew.com/3102.html Unity3D中一些指令碼的方法只能用在JS中,在C#中是無效的,而C#可以與伺服器端通訊,JS本身卻不行。而且,如果需要用到js呼叫c#的問題,js會比c#先編譯,所以在mac裡編譯ios的時候會出錯,

前臺js後臺C#互相呼叫 & JS於HTML互動

C#程式碼與javaScript函式的相互呼叫? 問: 1.如何在JavaScript訪問C#函式? 2.如何在JavaScript訪問C#變數? 3.如何在C#中訪問JavaScript的已有變數? 4.如何在C#中訪問JavaScript函式?問題1答案如下: ja

iOS webView的高階用法之JS互動,jsoc的相互呼叫(JavaScriptCore)

重要的事情放前面 github地址:https://github.com/horisea/JSCallOCTest   歡迎star 前言:說起JS互動,很多童鞋會黯然色變,感覺很高深的樣子。大部分小夥伴只知道一種,哪一種我也說說吧。    1.在webView中將要

cocos-jsandroid平臺互相呼叫

cocos-js中呼叫android平臺的介面:if (cc.sys.OS_ANDROID == cc.sys.os) { jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "

Android中ServiceActivity資料互動的簡單理解

Service跟Activity是最相似的元件,都代表可執行的程式,區別在於:Service一直在後臺執行,沒有跟使用者互動的介面。 啟動與停止Service有兩種方法: 第一種通過startService()與stopService()啟動和停止服務,Se

關於JS原生的offset的一些簡單理解

offset這個屬性,可以說是非常有用的,顧名思義,offset翻譯過來就是偏移量,從名字就可以看出它的具體意義了。也即是元素相當於父元素的偏移量。offset大致包括offsetTop、offsetLeft、offsetWidth、offsetHeight、offsetPa

iOS下JS原生OC互相呼叫(總結)

iOS開發免不了要與UIWebView打交道,然後就要涉及到JS與原生OC互動,今天總結一下JS與原生OC互動的兩種方式。 JS呼叫原生OC篇 方式一 第一種方式是用JS發起一個假的URL請求,然後利用UIWebView的代理方法攔截這次請求,然後

node.jsajax互動之 json jsonp 資料格式問題

將 dataType 從 json 改成 jsonp 之後,新的問題出現了,就是 ajax 無法解析 json 型別的資料。這就很尷尬了,看了好幾篇怎麼解析的問題,都沒看懂。後來終於看懂了。簡而言之就是 dataType 改成 jsonp 的資料格式以後,再傳 json 格式

資料庫應用伺服器分離的簡單理解

今天簡單瞭解了一下,站庫分離的意思。 應用伺服器即是WEB伺服器,可以理解為處理使用者的各種互動,可以為其配備更快更強大的CPU 檔案伺服器顧名思義就是儲存一些上穿的檔案(可以理解類似於雲盤儲存

iOS下JS原生OC互相呼叫

iOS開發免不了要與UIWebView打交道,然後就要涉及到JS與原生OC互動,今天總結一下JS與原生OC互動的兩種方式。 JS呼叫原生OC篇 方式一 第一種方式是用JS發起一個假的URL請求,然後利用UIWebView的代理方法攔截這次請求,然後再做相應的處理。

Android中webview jsnative方法互相呼叫

android webview允許js與native方法互相呼叫,基本的呼叫方法不再贅述,有個比較特殊的場景,記錄一下: 已經有一個完整的h5頁面,現在要將該頁面整合到app中,但是有部分h5頁面中的邏輯需要使用本地方法實現; 如果不想修改h5,可以通過如下方法: 1 首先

iOS開發-JS原生OC互相呼叫之問題總結二

今天繼續給同學們講解JS和OC的互相呼叫,今天給大家還是講解WKWebView中的一些使用,和注意點,廢話不多說直接上程式碼: #pragma mark - WKWebView中的MessageHandler? WKWebView初始化時,有一個引數叫configur

oracle學習之道:如何在ORACLE中非同步呼叫儲存過程的方法

 在ORACLE資料庫實際應用過程中,經常把業務處理邏輯的放在儲存過程,客戶端通過ADO進行呼叫。有些業務邏輯處理量大並且複雜,使客戶端呼叫儲存過程後,長時間沒有反應,也不知儲存過程執行狀態,本文講述如何在ORACLE通過任務和管道的應用,非同步呼叫儲存過程的方法。