84669 人學習
152542 人學習
20005 人學習
5487 人學習
7821 人學習
359900 人學習
3350 人學習
180660 人學習
48569 人學習
18603 人學習
40936 人學習
1549 人學習
1183 人學習
32909 人學習
同步不就是同步,非同步不就是非同步嗎?同步方式寫異步到底指什麼?
欢迎选择我的课程,让我们一起见证您的进步~~
非同步呼叫對於當前線程來說,是非阻礙的,所以要想知道非同步處理是否完成,或者是否出錯,通常都是透過事件或回調來實現的,這在 Node.js 比比皆是。 Ajax 就是很典型的非同步調用,以 jQuery.ajax 為例
$.getJSON("http://api.youapp.com/resouce1") .done(function(jo) { console.log("api resouce1 返回的是", jo); });
jQuery 的 Ajax 回傳的是 jQuery 的 Promise 對象,一般習慣上我們會使用 done() 回呼來處理呼叫完成之後的事情。但實際它也有標準Promise 的then(),所以上面的done 是可以改成then 的,但是要注意,done 是以事件的形式註冊回調,它返回當前這個Promise 物件,可以鍊式呼叫註冊若干個回呼。而 then 回傳的是另一個 Promise 物件(標準 Promise 規範),鍊式呼叫的話,每次呼叫並非作用在同一個 Promise 物件上。
done()
then()
done
then
如果在一個回調中需要進行另一個非同步調用,就需要在回調中註冊另一個回調。例如要取得某個數據,就需要先從api1 取得某個值,再用這個值去api2 取得某個資源,再用這個資源中的某個值去api3 取得這個值,這樣的回呼寫出來會像這樣:
$.getJSON("http://api.youapp.com/resouce1") .then(function(jo) { $.getJSON("http://api.youapp.com/resouce2?id=" + jo.blaId) .then(function(jo2) { $.getJSON("http://api.youapp.com/resouce3?xxx=" + jo2.xxxValue) .then(function(value) { console.log("总算拿到了", value); }); }); });
這才三層……很可怕的形式。這種形式被稱為「回調地獄」。
大家想了很多辦法來解決這種問題,Promise 就是其一,但是 Promise 仍然無法完全擺脫這種形式。 co 庫也是解決方案之一,同樣無法完美擺脫。
不過 ES2017 引入了 async/await,也就是所謂的以同步的形式寫異步,例如上面那段程式碼可以改寫成
async function xxx() { const jo = await $.getJSON("http://api.youapp.com/resouce1"); const jo2 = await $.getJSON("http://api.youapp.com/resouce2?id=" + jo.blaId); const value = await $.getJSON("http://api.youapp.com/resouce3?xxx=" + jo2.xxxValue); console.log("总算拿到了", value); }
async/await 消除了回調,所以看起來跟寫非異步(即同步)程式碼一樣。
參考:
閒聊非同步調用「扁平」化
從地獄到天堂,Node 回調轉向 async/await
理解 JavaScript 的 async/await
非同步時常見回呼函數嵌套,形如:
// 先读取 a fs.readFile('a.txt', (a) => { // a 读取成功后读取 b fs.readFile('b.txt', (b) => { // b 读取成功后读取 c fs.readFile('c.txt'. (c) => { console.log(a + b + c) }) }) })
這時出現了回調嵌套,需要一層一層往裡套,非常容易出錯且不好維護。
同步方式寫非同步類似:
function * asyncWrapper () { const a = yield read('a.txt') const b = yield read('b.txt') const c = yield read('c.txt') console.log(a + b + c) } // 使用形如 co 的库自动执行异步逻辑 co(asyncWrapper)
這時候非同步業務邏輯就透過正常的同步方式實現了。
同步方式寫非同步指得是程式碼的組織形式而已。使用async/await可以實現同步方式寫非同步,看下面程式碼:
const testAsync = async () => { const t = await f(); console.log(t); }; testAsync();
f是一個非同步操作,如果不使用async/await,直接同步的方式列印t,結果肯定是undefined;使用async/await之後,程式碼看上去形式還是同步的,但是裡面是先執行異步操作f,再印t的
f
undefined
樓上兩個答案足矣
非同步呼叫對於當前線程來說,是非阻礙的,所以要想知道非同步處理是否完成,或者是否出錯,通常都是透過事件或回調來實現的,這在 Node.js 比比皆是。 Ajax 就是很典型的非同步調用,以 jQuery.ajax 為例
jQuery 的 Ajax 回傳的是 jQuery 的 Promise 對象,一般習慣上我們會使用
done()
回呼來處理呼叫完成之後的事情。但實際它也有標準Promise 的then()
,所以上面的done
是可以改成then
的,但是要注意,done
是以事件的形式註冊回調,它返回當前這個Promise 物件,可以鍊式呼叫註冊若干個回呼。而then
回傳的是另一個 Promise 物件(標準 Promise 規範),鍊式呼叫的話,每次呼叫並非作用在同一個 Promise 物件上。如果在一個回調中需要進行另一個非同步調用,就需要在回調中註冊另一個回調。例如要取得某個數據,就需要先從api1 取得某個值,再用這個值去api2 取得某個資源,再用這個資源中的某個值去api3 取得這個值,這樣的回呼寫出來會像這樣:
這才三層……很可怕的形式。這種形式被稱為「回調地獄」。
大家想了很多辦法來解決這種問題,Promise 就是其一,但是 Promise 仍然無法完全擺脫這種形式。 co 庫也是解決方案之一,同樣無法完美擺脫。
不過 ES2017 引入了 async/await,也就是所謂的以同步的形式寫異步,例如上面那段程式碼可以改寫成
async/await 消除了回調,所以看起來跟寫非異步(即同步)程式碼一樣。
參考:
閒聊非同步調用「扁平」化
從地獄到天堂,Node 回調轉向 async/await
理解 JavaScript 的 async/await
非同步時常見回呼函數嵌套,形如:
這時出現了回調嵌套,需要一層一層往裡套,非常容易出錯且不好維護。
同步方式寫非同步類似:
這時候非同步業務邏輯就透過正常的同步方式實現了。
同步方式寫非同步指得是程式碼的組織形式而已。使用async/await可以實現同步方式寫非同步,看下面程式碼:
f
是一個非同步操作,如果不使用async/await,直接同步的方式列印t,結果肯定是undefined
;使用async/await之後,程式碼看上去形式還是同步的,但是裡面是先執行異步操作f,再印t的樓上兩個答案足矣