關於非同步請求的一些事

來源:互聯網
上載者:User

標籤:正是   fun   伺服器   red   判斷語句   called   fine   有一個   回呼函數   

先看這樣一個例子:

function foo() {    var result;    $.ajax({        url: ‘...‘,        success: function(response) {            result = response;        }    });    return result;}var result = foo(); // It always ends up being `undefined`.

在這個例子中,使用ajax進行非同步請求,但是響應的傳回值始終是undefined。那這是什麼原因呢?這個問題最初也讓我很困惑。下面我們來分析一下原因。

找出問題的原因

我們知道ajax中的a代表非同步,那就意味著發送請求(亦或是接受響應)需要花費一點時間。而在上述例子中,$.ajax是被立即返回的,return result; 這句語句在success 函數返迴響應前就已經被執行了。主要原因還是沒有理解非同步和同步之間的區別。

下面這個類比希望可以使同步和非同步區別更清晰。

Synchronous(同步流)

想象你給你的一個朋友打電話,你希望他可以幫你一個忙,你會進行一段時間的等待,直到他的回答。

那麼在正常同步流的代碼中也會發生一樣的事情。

function findItem() {    var item;    while(item_not_found) {        // search    }    return item;}var item = findItem();// Do something with itemdoSomethingElse();

執行 findItem 需要花費一段時間,所有在 var item = findItem(); 這條語句之後的代碼都需要等待函數返回結果。

Asynchronous(非同步流)

同樣你又給你的朋友打了一個電話,但是現在你很忙,你給你的朋友留言讓他給你回一個電話,然後你掛掉電話就做其他的事情了,直到你的朋友回你電話,你才會停下手中的事情處理這個電話。

這也正是ajax請求的過程。

findItem(function(item) {    // Do something with item});doSomethingElse();

不去等待響應而是立即繼續執行ajax之後的語句。而為了得到響應我們會定義一個回呼函數,一旦收到響應就會執行這個回呼函數。但是注意在ajax請求之後的語句會在回呼函數調用前被執行。

解決問題的方法1. 使用回呼函數

上面的例子中

var result = foo();// Code that depends on ‘result‘

改為

foo(function(result) {    // Code that depends on ‘result‘});

然後我們給 foo 傳遞函數參數

function myCallback(result) {    // Code that depends on ‘result‘}foo(myCallback);

函數 foo 定義如下

function foo(callback) {    $.ajax({        // ...        success: callback    });}

一旦ajax 請求成功,$.ajax 就會調用callback 函數並且將響應傳遞給callback 函數。

2.使用promise

Promise API是ES6新特性之一,但是各大瀏覽器已經有了很好的支援(IE11及以上支援)。MDN這麼定義它:

Promise 對象用於非同步計算。一個 Promise 表示一個現在、將來或永不可能可用的值

promise的文法:

new Promise(    /* executor */    function(resolve, reject) {...});

這裡是一段使用promise 的例子:

function delay() {        // `delay` returns a promise  return new Promise(function(resolve, reject) {        // Only `delay` is able to resolve or reject the promise    setTimeout(function() {      resolve(42);         // After 3 seconds, resolve the promise with value 42    }, 3000);  });}delay().then(function(v) {         // `delay` returns a promise      console.log(v);         // Log the value once it is resolved}).catch(function(v) {        // Or do something else if it is rejected         // (it would not happen in this example, since `reject` is not called).});

結合ajax 使用:

function ajax(url) {  return new Promise(function(resolve, reject) {    var xhr = new XMLHttpRequest();    xhr.onload = function() {      resolve(this.responseText);    };    xhr.onerror = reject;    xhr.open(‘GET‘, url);    xhr.send();  });}ajax("/echo/json").then(function(result) {  // Code depending on result}).catch(function() {  // An error occurred});

這裡有關於promise 的更多資訊。

3.jQuey: 使用延遲函數

jQery的延遲函數和promise 很像,但是API略有不同。每一個jQery的ajax方法都會返回一個延遲函數。

function ajax() {    return $.ajax(...);}ajax().done(function(result) {    // Code depending on result}).fail(function() {    // An error occurred});

始終要牢記promise 和延遲函數都只有一個存有未來值 的容器而不是值本身。看下面的例子:

function checkPassword() {    return $.ajax({        url: ‘/password‘,        data: {            username: $(‘#username‘).val(),            password: $(‘#password‘).val()        },        type: ‘POST‘,        dataType: ‘json‘    });}if (checkPassword()) {    // Tell the user they‘re logged in}

這段代碼就誤解了非同步和延遲過程,$.ajax() 會向伺服器發送對/password 的請求,jQery內部機制會立即會返回一個ajax延遲函數,而這個並不是伺服器發回來的響應。這也就意味著下面的判斷語句(if)始終都是true,程式會認為讀者已經登入,而這是不正確的。

我們可以進行一個小的修改:

checkPassword().done(function(r) {    if (r) {        // Tell the user they‘re logged in    } else {        // Tell the user their password was bad    }}).fail(function(x) {    // Tell the user something bad happened});

現在我們仍然會向伺服器發起請求,$.ajax() 也會立即返回一個延遲物件,但是我們通過監聽.done().fail() 事件能正確處理伺服器返回的響應。.done() 事件被調用時,伺服器返回的是一個正常的響應(http 200),我們通過檢查他的返回對象是否為true判斷使用者是否登陸。
.fail() 處理函數是處理一些錯誤的事件。例如使用者網路斷開或伺服器錯誤等。

本文代碼均來自StackOverflow上這個話題。

關於非同步請求的一些事

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.