javascript - 同步方式寫異步到底指什么?
問題描述
同步不就是同步,異步不就是異步嗎?同步方式寫異步到底指什么?
問題解答
回答1:異步調(diào)用對于當前線程來說,是非阻礙的,所以要想知道異步處理是否完成,或者是否出錯,通常都是通過事件或回調(diào)來實現(xiàn)的,這在 Node.js 比比皆是。Ajax 就是很典型的異步調(diào)用,以 jQuery.ajax 為例
$.getJSON('http://api.youapp.com/resouce1') .done(function(jo) {console.log('api resouce1 返回的是', jo); });
jQuery 的 Ajax 返回的是 jQuery 的 Promise 對象,一般習慣上我們會使用 done() 回調(diào)來處理調(diào)用完成之后的事情。但實際它也有標準 Promise 的 then(),所以上面的 done 是可以改成 then 的,但是要注意,done 是以事件的形式注冊回調(diào),它返回當前這個 Promise 對象本身,可以鏈式調(diào)用注冊若干個回調(diào)。而 then 返回的是另一個 Promise 對象(標準 Promise 規(guī)范),鏈式調(diào)用的話,每次調(diào)用并非作用在同一個 Promise 對象上。
如果在一個回調(diào)中需要進行另一個異步調(diào)用,就需要在回調(diào)中注冊另一個回調(diào)。比如要獲取某個數(shù)據(jù),需要先從 api1 獲取某個值,再用這個值去 api2 獲取某個資源,再用這個資源中的某個值去 api3 獲取這個值,這樣的回調(diào)寫出來會像這樣:
$.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); }); }); });
這才三層……很可怕的形式。這種形式被稱為“回調(diào)地獄”。
大家想了很多辦法來解決這種問題,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 消除了回調(diào),所以看起來跟寫非異步(即同步)代碼一樣。
參考:
閑談異步調(diào)用“扁平”化
從地獄到天堂,Node 回調(diào)向 async/await 轉(zhuǎn)變
理解 JavaScript 的 async/await
回答2:異步時常見回調(diào)函數(shù)嵌套,形如:
// 先讀取 afs.readFile(’a.txt’, (a) => { // a 讀取成功后讀取 b fs.readFile(’b.txt’, (b) => { // b 讀取成功后讀取 c fs.readFile(’c.txt’. (c) => { console.log(a + b + c) }) })})
這時出現(xiàn)了回調(diào)嵌套,需要一層一層往里套,非常容易出錯且不好維護。
同步方式寫異步類似于:
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 的庫自動執(zhí)行異步邏輯co(asyncWrapper)
這時候異步業(yè)務邏輯就通過正常的同步方式實現(xiàn)了。
回答3:同步方式寫異步指得是代碼的組織形式而已。使用async/await可以實現(xiàn)同步方式寫異步,看下面代碼:
const testAsync = async () => { const t = await f(); console.log(t);};testAsync();
f是一個異步操作,如果不使用async/await,直接同步的方式打印t,結果肯定是undefined;使用async/await之后,代碼看上去形式還是同步的,但是里面是先執(zhí)行異步操作f,再打印t的
回答4:樓上兩個答案足矣
相關文章:
1. 我的html頁面一提交,網(wǎng)頁便顯示出了我的php代碼,求問是什么原因?2. 我在centos容器里安裝docker,也就是在容器里安裝容器,報錯了?3. 數(shù)據(jù)庫 - 使用讀寫分離后, MySQL主從復制延遲會導致讀不到數(shù)據(jù)嗎?4. tp6表單令牌5. docker 17.03 怎么配置 registry mirror ?6. 老哥們求助啊7. django - 后臺返回的json數(shù)據(jù)經(jīng)過Base64加密,獲取時用python如何解密~!8. node.js - node 客戶端socket一直報錯Error: read ECONNRESET,用php的socket沒問題哈。。9. 如何解決docker宿主機無法訪問容器中的服務?10. javascript - canvas 可以實現(xiàn) PS 魔法橡皮擦的功能嗎?
