成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入探析koa之異步回調處理篇

開發 前端
在上一篇中我們梳理了koa當中中間件的洋蔥模型執行原理,并實現了一個可以讓洋蔥模型自動跑起來的流程管理函數。這一篇,我們再來研究一下koa當中異步回調同步化寫法的原理,同樣的,我們也會實現一個管理函數,是的我們能夠通過同步化的寫法來寫異步回調函數。

 

[[176864]]

在上一篇中我們梳理了koa當中中間件的洋蔥模型執行原理,并實現了一個可以讓洋蔥模型自動跑起來的流程管理函數。這一篇,我們再來研究一下koa當中異步回調同步化寫法的原理,同樣的,我們也會實現一個管理函數,是的我們能夠通過同步化的寫法來寫異步回調函數。

1. 回調金字塔及理想中的解決方案

我們都知道javascript是一門單線程異步非阻塞語言。異步非阻塞當然是它的一個優點,但大量的異步操作必然涉及大量的回調函數,特別是當異步嵌套的時候,就會出現回調金字塔的問題,使得代碼的可讀性非常差。比如下面一個例子:

  1. var fs = require('fs'); 
  2.  
  3. fs.readFile('./file1'function(err, data) { 
  4.   console.log(data.toString()); 
  5.   fs.readFile('./file2'function(err, data) { 
  6.     console.log(data.toString()); 
  7.   }) 
  8. })  

這個例子是先后讀取兩個文件內容并打印,其中file2的讀取必須在file1讀取結束之后再進行,因此其操作必須要在file1讀取的回調函數中執行。這是一個典型的回調嵌套,并且只有兩層而已,在實際編程中,我們可能會遇到更多層的嵌套,這樣的代碼寫法無疑是不夠優雅的。

在我們想象中,比較優雅的一種寫法應該是看似同步實則異步的寫法,類似下面這樣:

  1. var data; 
  2. data = readFile('./file1'); 
  3. //下面的代碼是***個readFile執行完畢之后的回調部分 
  4. console.log(data.toString()); 
  5. //下面的代碼是第二個readFile的回調 
  6. data = readFile('./file2'); 
  7. console.log(data.toString());  

這樣的寫法,就完全避免回調地獄。事實上,koa就讓我們可以使用這樣的寫法來寫異步回調函數:

  1. var koa = require('koa'); 
  2. var app = koa(); 
  3. var request=require('some module'); 
  4.  
  5. app.use(function*() { 
  6.   var data = yield request('http://www.baidu.com'); 
  7.   //以下是異步回調部分 
  8.   this.body = data.toString(); 
  9. }) 
  10.  
  11. app.listen(3000); 

那么,究竟是什么讓koa有這么神奇的魔力呢?

2. generator配合promise實現異步回調同步寫法

關鍵的一點,其實前一篇也提到了,就是generator具有類似"打斷點"這樣的效果。當遇到yield的時候,就會暫停,將控制權交給yield后面的函數,當下次返回的時候,再繼續執行。

而在上面的那個koa例子中,yield后面的可不是任何對象都可以哦!必須是特定類型。在co函數中,可以支持promise, thunk函數等。

今天的文章中,我們就以promise為例來進行分析,看看如何使用generator和promise配合,實現異步同步化。

依舊以***個讀取文件例子來分析。首先,我們需要將讀文件的函數進行改造,將其封裝成為一個promise對象:

  1. var fs = require('fs'); 
  2.  
  3. var readFile = function(fileName) { 
  4.   return new Promise(function(resolve, reject) { 
  5.     fs.readFile(fileName, function(err, data) { 
  6.       if (err) { 
  7.         reject(err); 
  8.       } else { 
  9.         resolve(data); 
  10.       } 
  11.     }) 
  12.   }) 
  13.  
  14. //下面是readFile使用的示例 
  15. var tmp = readFile('./file1'); 
  16. tmp.then(function(data) { 
  17.   console.log(data.toString()); 
  18. })  

關于promise的使用,如果不熟悉的可以去看看es6中的語法。(近期我也會寫一篇文章來教大家如何用es5的語法來自己實現一個具備基本功能的promise對象,敬請期待呦^_^)

簡單來講,promise可以實現將回調函數通過 promise.then(callback)的形式來寫。但是我們的目標是配合generator,真正實現如絲般順滑的同步化寫法,如何配合呢,看這段代碼:

  1. var fs = require('fs'); 
  2.  
  3. var readFile = function(fileName) { 
  4.   return new Promise(function(resolve, reject) { 
  5.     fs.readFile(fileName, function(err, data) { 
  6.       if (err) { 
  7.         reject(err); 
  8.       } else { 
  9.         resolve(data); 
  10.       } 
  11.     }) 
  12.   }) 
  13.  
  14. //將讀文件的過程放在generator中 
  15. var gen = function*() { 
  16.   var data = yield readFile('./file1'); 
  17.   console.log(data.toString()); 
  18.   data = yield readFile('./file2'); 
  19.   console.log(data.toString()); 
  20.  
  21. //手動執行generator 
  22. var g = gen(); 
  23. var another = g.next(); 
  24. //another.value就是返回的promise對象 
  25. another.value.then(function(data) { 
  26.   //再次調用g.next從斷點處執行generator,并將data作為參數傳回 
  27.   var another2 = g.next(data); 
  28.   another2.value.then(function(data) { 
  29.     g.next(data); 
  30.   }) 
  31. })  

上述代碼中,我們在generator中yield了readFile,回調語句代碼寫在yield之后的代碼中,完全是同步的寫法,實現了文章一開頭的設想。

而yield之后,我們得到的是一個another.value是一個promise對象,我們可以使用then語句定義回調函數,函數的內容呢,則是將讀取到的data返回給generator并繼續讓generator從斷點處執行。

基本上這就是異步回調同步化最核心的原理,事實上如果大家熟悉python,會知道python中有"協程"的概念,基本上也是使用generator來實現的(我想當懷疑es6的generator就是借鑒了python~)

不過呢,上述代碼我們依然是手動執行的。那么同上一篇一樣,我們還需要實現一個run函數,用于管理generator的流程,讓它能夠自動跑起來!

3. 讓同步化回調函數自動跑起來:一個run函數的編寫

仔細觀察上一段代碼中手動執行generator的部分,也能發現一個規律,這個規律讓我們可以直接寫一個遞歸的函數來代替:

  1. var run=function(gen){ 
  2.   var g; 
  3.   if(typeof gen.next==='function'){ 
  4.     g=gen; 
  5.   }else
  6.     g=gen(); 
  7.   } 
  8.  
  9.   function next(data){ 
  10.     var tmp=g.next(data); 
  11.     if(tmp.done){ 
  12.       return ; 
  13.     }else
  14.       tmp.value.then(next); 
  15.     } 
  16.   } 
  17.  
  18.   next(); 
  19.  

函數接收一個generator,并讓其中的異步能夠自動執行。使用這個run函數,我們來讓上一個異步代碼自動執行:

  1. var fs = require('fs'); 
  2.  
  3. var run = function(gen) { 
  4.   var g; 
  5.   if (typeof gen.next === 'function') { 
  6.     g = gen; 
  7.   } else { 
  8.     g = gen(); 
  9.   } 
  10.  
  11.   function next(data) { 
  12.     var tmp = g.next(data); 
  13.     if (tmp.done) { 
  14.       return
  15.     } else { 
  16.       tmp.value.then(next); 
  17.     } 
  18.   } 
  19.  
  20.   next(); 
  21.  
  22. var readFile = function(fileName) { 
  23.   return new Promise(function(resolve, reject) { 
  24.     fs.readFile(fileName, function(err, data) { 
  25.       if (err) { 
  26.         reject(err); 
  27.       } else { 
  28.         resolve(data); 
  29.       } 
  30.     }) 
  31.   }) 
  32.  
  33. //將讀文件的過程放在generator中 
  34. var gen = function*() { 
  35.   var data = yield readFile('./file1'); 
  36.   console.log(data.toString()); 
  37.   data = yield readFile('./file2'); 
  38.   console.log(data.toString()); 
  39. //下面只需要將gen放入run當中即可自動執行 
  40. run(gen);  

執行上述代碼,即可看到終端依次打印出了file1和file2的內容。

需要指出的是,這里的run函數為了簡單起見只支持promise,而實際的co函數還支持thunk等。

這樣一來,co函數的兩大功能基本就完整介紹了,一個是洋蔥模型的流程控制,另一個是異步同步化代碼的自動執行。在下一篇文章中,我將帶大家對這兩個功能進行整合,寫出我們自己的一個co函數!

這篇文章的代碼同樣可以在github上面找到:https://github.com/mly-zju/async-js-demo,其中promise_generator.js就是本篇的示例源碼。

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2019-03-18 09:50:44

Nginx架構服務器

2018-11-29 08:00:20

JavaScript異步Promise

2022-01-02 09:29:37

模型洋蔥Koa

2009-06-08 10:20:01

Hibernate查詢

2012-05-30 13:26:12

HTML5

2012-05-30 13:49:52

HTML5

2012-05-30 14:51:09

HTML5

2012-05-31 09:19:22

HTML5

2012-05-31 09:54:13

HTML5

2012-05-31 10:57:06

HTML5

2012-11-12 10:32:48

IBMdw

2012-05-30 15:17:54

HTML5

2012-05-31 09:35:43

HTML5

2024-01-31 08:09:53

預處理器代碼C++

2018-04-20 16:15:42

Koa2上傳下載

2009-08-21 17:02:20

ASP.NET異步回調

2015-10-26 09:25:42

2010-01-14 09:15:07

Java EE 6Servlet 3.0異步處理

2017-06-06 15:34:41

物聯網數據庫壓縮

2017-06-05 14:50:33

大數據數據庫壓縮
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线不卡 | 精品久久久久久亚洲精品 | 久久午夜精品 | 国产成人精品一区二 | 日韩在线欧美 | 欧美一级淫片免费视频黄 | 亚洲啊v在线 | 五月精品视频 | 成人自拍视频网站 | 2020天天操 | 日韩精品免费视频 | 精品一二三区视频 | 福利在线观看 | 日日操网站| 九九国产 | 精品福利一区 | 波多野吉衣在线播放 | 亚洲电影免费 | 精品无码三级在线观看视频 | 影音先锋亚洲资源 | 亚洲欧美一区二区三区1000 | 日韩精品在线视频 | 激情国产在线 | 成人久久18免费网站 | 凹凸日日摸日日碰夜夜 | 亚洲欧美日韩国产综合 | 98久久 | 国产欧美一区二区三区在线看 | 国内av在线 | 四虎海外 | 日韩欧美国产精品 | 日本一区二区高清不卡 | 亚洲日韩视频 | 日本精品视频一区二区 | 国产精品久久久久久久久久免费看 | 久久久久香蕉视频 | 国产精品久久久久久久久久 | 国产一级片 | 国产精品黄色 | 精品成人av | 久久国产精品99久久久久久丝袜 |