異步,它的孿生兄弟--同步(Synchronous),"同步模式"就是上一段的模式,後一個任務等待前一個任務結束,而後再執行,程序的執行順序與任務的排列順序是一致的、同步的.javascript
"異步模式"則徹底不一樣,每個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,因此程序的執行順序與任務的排列順序是不一致的、異步的。 "異步模式"很是重要。在瀏覽器端,耗時很長的操做都應該異步執行,避免瀏覽器失去響應,最好的例子就是Ajax操做。就如今來講應該沒有什麼後臺服務器仍是同步操做了...html
用最直觀的代碼來體現:前端
1 <body> 2 <button id="Button">展現異步操做</button> 3 <script> 4 var Button=document.getElementById('Button'); 5 Button.onclick=function(){ 6 alert('展現異步操做--a'); 7 } 8 alert('展現異步操做--b'); 9 </script> 10 </body>
這個簡單的例子就體現出了異步和同步的區別了:java
咱們日常寫的代碼,都是從上到下來執行的,通常上面的語句尚未執行結束的狀況下,下面的語句是不會執行的,可是這段代碼咱們很容易測試出:先彈出b窗口,當你點擊按鈕的時候纔開始彈出a窗口。 這就是典型的異步操做,不用等把上面的語句所有執行完纔開始執行下面的語句。jquery
Javascript 採用回調函數(callback)來處理異步編程。從同步編程到異步回調編程有一個適應的過程,可是若是出現多層回調嵌套,也就是咱們常說的厄運的回調金字塔(Pyramid of Doom),絕對是一種糟糕的編程體驗。因而便有了 CommonJS 的 Promises/A 規範,用於解決回調金字塔問題。本文先介紹 Promises 相關規範,而後再經過解讀一個迷你的 Promises 以加深理解。程序員
一個 Promise 對象表明一個目前還不可用,可是在將來的某個時間點能夠被解析的值。它容許你以一種同步的方式編寫異步代碼。例如,若是你想要使用 Promise API 異步調用一個遠程的服務器,你須要建立一個表明數據將會在將來由 Web 服務返回的 Promise 對象。惟一的問題是目前數據還不可用。當請求完成並從服務器返回時數據將變爲可用數據。在此期間,Promise 對象將扮演一個真實數據的代理角色。接下來,你能夠在 Promise 對象上綁定一個回調函數,一旦真實數據變得可用這個回調函數將會被調用。ajax
Promise 對象曾經以多種形式存在於許多語言中。算法
Javascript 中最多見的反模式作法是回調內部再嵌套回調。編程
1 // 回調金字塔 2 asyncOperation(function(data){ 3 // 處理 `data` 4 anotherAsync(function(data2){ 5 // 處理 `data2` 6 yetAnotherAsync(function(){ 7 // 完成 8 }); 9 }); 10 });
引入 Promises 以後的代碼api
1 promiseSomething() 2 .then(function(data){ 3 // 處理 `data` 4 return anotherAsync(); 5 }) 6 .then(function(data2){ 7 // 處理 `data2` 8 return yetAnotherAsync(); 9 }) 10 .then(function(){ 11 // 完成 12 });
Promises 將嵌套的 callback,改形成一系列的.then的連綴調用,去除了層層縮進的糟糕代碼風格。Promises 不是一種解決具體問題的算法,而已一種更好的代碼組織模式。接受新的組織模式同時,也逐漸以全新的視角來理解異步調用。
Fetch API 提供了一個獲取資源的接口(包括跨域)。任何使用過 XMLHttpRequest
的人都能輕鬆上手,但新的API提供了更強大和靈活的功能集。
Fetch 提供了對 Request
和 Response
(以及其餘與網絡請求有關的)對象的通用定義。使之從此能夠被使用到更多地應用場景中:不管是service workers、Cache API、又或者是其餘處理請求和響應的方式,甚至是任何一種須要你本身在程序中生成響應的方式。
它還提供了一種定義,將 CORS 和 HTTP 原生的頭信息結合起來,取代了原來那種分離的定義。
閉包和詞法做用域很是相近。一個關於閉包如何工做的更好或者更實際的例子就是返回一個函數的引用。
咱們能夠返回域中的東西,使得它們能夠被其父域所用。
當你在函數裏聲明一個變量時,你只能在函數內訪問。這些變量的做用域就被限制在函數裏了。
若是你在一個函數內又定義了內部函數,那麼這個內部函數就被稱做閉包。它仍能夠訪問外部函數的做用域。
1 var xhr; 2 if (window.XMLHttpRequest) { // Mozilla, Safari... 3 xhr = new XMLHttpRequest(); 4 } else if (window.ActiveXObject) { // IE 5 try { 6 xhr = new ActiveXObject('Msxml2.XMLHTTP'); 7 } catch (e) { 8 try { 9 xhr = new ActiveXObject('Microsoft.XMLHTTP'); 10 } catch (e) {} 11 } 12 } 13 if (xhr) { 14 xhr.onreadystatechange = onReadyStateChange; 15 xhr.open('POST', '/api', true); 16 // 設置 Content-Type 爲 application/x-www-form-urlencoded 17 // 以表單的形式傳遞數據 18 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 19 xhr.send('username=admin&password=root'); 20 } 21 22 // onreadystatechange 方法 23 function onReadyStateChange() { 24 // 該函數會被調用四次 25 console.log(xhr.readyState); 26 if (xhr.readyState === 4) { 27 // everything is good, the response is received 28 if (xhr.status === 200) { 29 console.log(xhr.responseText); 30 } else { 31 console.log('There was a problem with the request.'); 32 } 33 } else { 34 // still not ready 35 console.log('still not ready...'); 36 } 37 }
從上邊的代碼能夠看出,XMLHttpRequest 是一個很是粗糙的API,不符合關注分離的原則,配置和調用方式很是混亂,前端程序員們不只要作各個瀏覽器的兼容性,還飽受回調地獄的折磨,這顯然不是一個好的選擇。
1 fetch(...).then(fun2) 2 .then(fun3) //各依賴有序執行 3 ..... 4 .catch(fun)
從上邊的代碼能夠看出,fetch解決了回調地獄問題,使用簡便,雖然仍是有Callback的影子,可是看起來舒服多了。
Fetch 優勢: