中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何深入探析koa中的異步回調處理

發布時間:2021-11-16 17:28:00 來源:億速云 閱讀:124 作者:柒染 欄目:web開發

本篇文章給大家分享的是有關如何深入探析koa中的異步回調處理,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

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

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

var fs = require('fs');  fs.readFile('./file1', function(err, data) {   console.log(data.toString());   fs.readFile('./file2', function(err, data) {     console.log(data.toString());   }) })

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

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

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

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

var koa = require('koa'); var app = koa(); var request=require('some module');  app.use(function*() {   var data = yield request('http://www.baidu.com');   //以下是異步回調部分   this.body = data.toString(); })  app.listen(3000);

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

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

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

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

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

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

var fs = require('fs');  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //下面是readFile使用的示例 var tmp = readFile('./file1'); tmp.then(function(data) {   console.log(data.toString()); })

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

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

var fs = require('fs');  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //將讀文件的過程放在generator中 var gen = function*() {   var data = yield readFile('./file1');   console.log(data.toString());   data = yield readFile('./file2');   console.log(data.toString()); }  //手動執行generator var g = gen(); var another = g.next(); //another.value就是返回的promise對象 another.value.then(function(data) {   //再次調用g.next從斷點處執行generator,并將data作為參數傳回   var another2 = g.next(data);   another2.value.then(function(data) {     g.next(data);   }) })

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

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

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

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

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

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

var run=function(gen){   var g;   if(typeof gen.next==='function'){     g=gen;   }else{     g=gen();   }    function next(data){     var tmp=g.next(data);     if(tmp.done){       return ;     }else{       tmp.value.then(next);     }   }    next(); }

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

var fs = require('fs');  var run = function(gen) {   var g;   if (typeof gen.next === 'function') {     g = gen;   } else {     g = gen();   }    function next(data) {     var tmp = g.next(data);     if (tmp.done) {       return;     } else {       tmp.value.then(next);     }   }    next(); }  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //將讀文件的過程放在generator中 var gen = function*() {   var data = yield readFile('./file1');   console.log(data.toString());   data = yield readFile('./file2');   console.log(data.toString()); } //下面只需要將gen放入run當中即可自動執行 run(gen);

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

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

這樣一來,co函數的兩大功能基本就完整介紹了,一個是洋蔥模型的流程控制,另一個是異步同步化代碼的自動執行。

以上就是如何深入探析koa中的異步回調處理,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

koa
AI

水城县| 房产| 泗阳县| 阳高县| 慈溪市| 措勤县| 榆树市| 台中县| 吉隆县| 浦北县| 温州市| 勐海县| 永安市| 邢台市| 叙永县| 芮城县| 韶关市| 收藏| 同江市| 子洲县| 九台市| 焦作市| 宜兰市| 邯郸市| 涞源县| 绥滨县| 宁安市| 景宁| 赞皇县| 山东| 珠海市| 金沙县| 克东县| 开远市| 无极县| 麻栗坡县| 库尔勒市| 东乌珠穆沁旗| 普格县| 黄大仙区| 临邑县|