2013-07-22 81 views
3

有沒有辦法執行不凍結瀏覽器的同步AJAX查詢?在我看來,在大多數情況下,同步請求更容易處理,但是阻止其他代碼執行的事實是一個真正的殺手。有沒有辦法讓同步AJAX沒有負面影響? (是的,我意識到術語「同步AJAX」是一個矛盾)。非阻塞同步AJAX

+4

我不這麼認爲......我建議你學習承諾,使AJAX工作更容易。 – elclanrs

+0

@hexacyanide對不起,我猜這是措辭不佳。我的意思是它不凍結瀏覽器或阻止我的代碼中的其他事件觸發。 – Ajedi32

+0

即使「非阻塞同步」不是矛盾,在單執行(又名單線程)環境中這樣的構造是不可能的。瀏覽器JavaScript中的替代方案和解決方案實際上是「非阻塞*異步*」。 – user2246674

回答

2

我會舉一個允許這種行爲的壞結果的例子。

比方說你有這樣的程序:

<script> 
var file = "foo.json"; 

function nullIt() { 
    file = null; 
} 

function loadFile() { 
    if (file != null) { 
     synchronousLoad(file);//imagine the load takes 5 seconds 
     alert("i just loaded: " + file); 
    } 
} 

window.onload = loadFile; 
</script> 
<button onclick="nullIt()">click me</button> 

壞事這裏 -

  • synchronousLoad()阻止5秒,用戶點擊該按鈕,事件處理程序跑得快完成。
  • 現在file變量爲空。
  • synchronousLoad()飾面和回報,對代碼
  • file下一行讓執行履歷是現在爲空,並且該消息輸出給用戶是斷開的。

真正的問題在這裏你不能以同樣的方式推理你的代碼了。僅僅因爲第5行的一些事實是 是真的,並不意味着它在下一行仍然是真的。這使得編寫一個無錯誤的程序非常困難。

一些編程語言支持多線程,並且您必須處理這些問題,儘管您有工具來幫助處理這些問題。但是,對於程序員來說,這還是很多額外的工作。

比較而言,使用回調來執行異步操作是ez-mode。

+1

啊,優點。就我個人而言,我寧願把這些「競爭條件」(如果你可以稱之爲)的機會,但很高興看到爲什麼事情是這樣的理由。 – Ajedi32

3

否。根據定義,同步是阻塞的。在流程完成之前,任何事情都可以繼續。這包括Web瀏覽器中的其他用戶界面。

它的假設是異步的,所以最好的方法是設計代碼異步工作。

1

我不認爲這是可能的。您可以使用異步方法並使用AJAX完成事件,而不是嘗試使用同步查詢。使用jQuery.ajax()

jQuery.ajax({ 
    url: "URL HERE", 
    data: "whatever you are sending" 
}).done(function (data) { 
    // Do things with data 
}); 

因此,代替使用一個同步請求,則可以使用異步請求和之後的請求已經完成剛剛執行代碼。所以,它不會凍結你的瀏覽器。

+0

是的,但這正是我試圖通過做一個同步請求避免。我的代碼的當前執行路徑中沒有任何內容需要執行,直到請求完成後才執行同步請求。 我只是不希望它在等待時阻止我的代碼的其他部分。 – Ajedi32

+0

@ Ajedi32它根本不乾淨 - 特別是因爲它*不能用單個執行上下文(例如瀏覽器JavaScript使用的上下文)工作。另外,當使用多個執行上下文時(即線程或者延續),還有其他的考慮和問題需要處理:隱式的原子執行被刪除,並且[更多形式的]競爭條件必須被防範。 – user2246674

+1

@ Ajedi32使用promise(特別是在jQuery 1.8+中實現並由[Promises/A](http://wiki.commonjs.org/wiki/Promises/A)編寫的'then')可以極大地清理異步代碼用法。我發現Promise模型比以前的成功/錯誤回調要更加一致和乾淨。 – user2246674

0

由於其他答案中列出的原因,在沒有阻止瀏覽器中的其他事件的情況下,沒有辦法執行同步AJAX調用。但是,如果代碼複雜性是您希望避免異步方法調用的主要原因,那麼您可能對Javascript交叉編譯器streamline.js感興趣,它允許您編寫異步方法調用,就好像它們是同步的,並獲取結果與您異步編寫該調用的結果相同。

從項目的GitHub的頁面:

streamline.js是一種語言工具,以簡化異步JavaScript編程 。

而不是寫像毛毛代碼:

function archiveOrders(date, cb) { 
    db.connect(function(err, conn) { 
    if (err) return cb(err); 
    conn.query("select * from orders where date < ?", [date], function(err, orders) { 
     if (err) return cb(err); 
     helper.each(orders, function(order, next) { 
     conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) { 
      if (err) return cb(err); 
      conn.execute("delete from orders where id=?", [order.id], function(err) { 
      if (err) return cb(err); 
      next(); 
      }); 
     }); 
     }, function() { 
     console.log("orders have been archived"); 
     cb(); 
     }); 
    }); 
    }); 
} 

你寫:

function archiveOrders(date, _) { 
    var conn = db.connect(_); 
    conn.query("select * from orders where date < ?", [date], _).forEach_(_, function(_, order) { 
    conn.execute("insert into archivedOrders ...", [order.id, ...], _); 
    conn.execute("delete from orders where id=?", [order.id], _); 
    }); 
    console.log("orders have been archived"); 
} 

和精簡轉換代碼,需要回調的關懷!

沒有控制流API來學習!你只需要遵循一個簡單的規則:

用下劃線替換所有的回調函數,並寫下你的代碼,好像所有的 函數都是同步的。

有關streamline.js更多信息,閱讀博客文章Asynchronous Javascript – the tale of Harry

1

在即將發佈的ECMAScript 2016(ES7)標準中,有一組新的語言關鍵字設計用於執行與您看起來非常相似的操作,稱爲asyncawait

這些關鍵字允許「非阻塞同步AJAX」,但他們讓你寫異步代碼的方式,看起來同步。這裏有一個簡單的例子:

// Let's say you have an asynchronous function that you want to call in a synchronous 
// style... 
function delayedEval(delay, func) { 
    // First, ensure that the function returns a Promise object. If it doesn't, wrap it with 
    // another function that does. 
    return new Promise((resolve, reject) => { 
    setTimeout(() => resolve(func()), delay) 
    }) 
    // For more on Promises, see https://goo.gl/uaoDuy (MDN link) 
} 

// Then, declare a function as asynchronous. This causes it to return a Promise that 
// resolves to its return value, instead of returning its return value directly. 
async function delayedHello() { 
    // Inside an async function, you can call other async functions like this, which looks 
    // very much like a synchronous call (even though it isn't). 
    let message = await delayedEval(1500,() => "Hello, world!") 
    console.log(message) 
} 

// This returns (a Promise) immediately, but doesn't print "Hello, world!" until 1.5 
// seconds later. (At which point it resolves the Promise.) 
delayedHello() 

Try in Babel

基本上,而不是「無不良副作用同步AJAX」,asyncawait讓你異步 AJAX沒有所有負面影響。 (具有許多用於處理回調的邏輯的亂碼)。

asyncawait是ES7標準中"async functions" candidate recommendation的一部分。