2021年7月25日 星期日

jQuery同步Ajax阻塞問題及解決辦法

 由於開發JavaScript是單線程的,當我們使用Ajax同步請求時,線程將停在等待請求response的地方,直到收到response,線程才繼續執行。

這導致了程序無法執行其他js命令, 帶來了線程阻塞問題,具體體現方式是UI界面卡住。  這裏的ajax不能用異步的,否則函數返回時,result還未賦值,會出錯。所以加了async:false。但是帶來的另一個問題就是線程阻塞。如下:

function getData(){ var result; $.ajax({ url : 'p.php', async : false, success: function(data){ result = data; } }); return result; }

找了一下資料,發現幾種方法都可以完美解決問題,具體代碼如下:

Deferred:

function getData(){ var defer = $.Deferred(); $.ajax({ url : 'p.php', //async : false, success: function(data){ defer.resolve(data) } }); return defer.promise(); } // getData()返回Promise對象 $.when(getData()).done(function(data){ alert(data); });

Promise:

getData() { return new Promise((resolve, reject) => { $.ajax({ url : 'p.php', //async : false, success: function(data){ defer.resolve(data) }, error: function(result) { reject("throw error") } }) }) } // 調用 getData().then(function(data){ console.log(data) }).catch(function(err){ console.log(err) })

在ES6中,還可以使用Generator來創建異步編程

function* getData() { let result; $.ajax({ url : 'p.php', success: function(data){ result = data; } }); yield; return result } var gd = getData() console.log(gd.next()) // {value: undefined, done: false} console.log(gd.next()) // {value: data, done: false}

2021年7月24日 星期六

jQuery.ajax處理繼續響應:“success:”vs“.done”?

success一直是jQuery成功回調的傳統名稱,定義為ajax調用中的一個選項。但是,由於$.Deferreds和更複雜的回調的實現,done是實現成功回調的首選方法,因為它可以在任何deferred上調用。


例如,成功:

$.ajax({
  url: '/',
  success: function(data) {}
});

例如,完成:

$.ajax({url: '/'}).done(function(data) {});

關於done的好處是$.ajax的返回值現在是一個延遲的promise,可以綁定到應用程序中的任何其他位置。所以,假設你想從幾個不同的地方進行這個ajax調用。而不是將成功函數作為執行此ajax調用的函數的選項傳遞,您可以讓函數返回$.ajax本身並使用done,fail,then或其他任何內容綁定回調。請注意,always是一個回調,無論請求成功還是失敗,它都將運行。 done僅在成功時觸發。

例如:

function xhr_get(url) {
  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json',
    beforeSend: showLoadingImgFn
  })
  .always(function() {
    // remove loading image maybe
  })
  .fail(function() {
    // handle request failures
  });

}

xhr_get('/index').done(function(data) {
  // do stuff with index data
});

xhr_get('/id').done(function(data) {
  // do stuff with id data
});

在可維護性方面,這一點的一個重要好處是,您已將ajax機制包裝在特定於應用程序的函數中。如果你決定將來需要$.ajax調用以不同的方式運行,或者你使用不同的ajax方法,或者你不再使用jQuery,你只需要更改xhr_get定義(確保返回一個承諾或至少一種done方法,在上述例子的情況下)。整個應用程序中的所有其他引用可以保持不變。


使用$.Deferred可以做更多(更酷)的事情,其中??一個是使用then來觸發服務器報告的錯誤,即使$.ajax請求本身成功。例如:

function xhr_get(url) {
  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json'
  })
  .then(function(data) {
    return data.responseCode != 200 ?
      $.Deferred().reject( data ) :
      data;
  })
  .fail(function(data) {
    if ( data.responseCode )
      console.log( data.responseCode );
  });
}

xhr_get('/index').done(function(data) {
  // will not run if json returned from ajax has responseCode other than 200
});