最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析koa之異步回調(diào)處理

 更新時間:2019年06月17日 10:03:43   作者:勇敢的半導體  
這篇文章主要介紹了深入解析koa之異步回調(diào)處理,我們研究一下koa當中異步回調(diào)同步化寫法的原理,同樣的,我們也會實現(xiàn)一個管理函數(shù),是的我們能夠通過同步化的寫法來寫異步回調(diào)函數(shù)。,需要的朋友可以參考下

1. 回調(diào)金字塔及理想中的解決方案

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

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

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

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

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

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

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

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

2. generator配合promise實現(xiàn)異步回調(diào)同步寫法

關(guān)鍵的一點,其實前一篇也提到了,就是generator具有類似"打斷點"這樣的效果。當遇到y(tǒng)ield的時候,就會暫停,將控制權(quán)交給yield后面的函數(shù),當下次返回的時候,再繼續(xù)執(zhí)行。

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

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

依舊以第一個讀取文件例子來分析。首先,我們需要將讀文件的函數(shù)進行改造,將其封裝成為一個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());
})

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

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

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());
}
//手動執(zhí)行g(shù)enerator
var g = gen();
var another = g.next();
//another.value就是返回的promise對象
another.value.then(function(data) {
//再次調(diào)用g.next從斷點處執(zhí)行g(shù)enerator,并將data作為參數(shù)傳回
var another2 = g.next(data);
another2.value.then(function(data) {
g.next(data);
})
})

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

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

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

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

3. 讓同步化回調(diào)函數(shù)自動跑起來:一個run函數(shù)的編寫

仔細觀察上一段代碼中手動執(zhí)行g(shù)enerator的部分,也能發(fā)現(xiàn)一個規(guī)律,這個規(guī)律讓我們可以直接寫一個遞歸的函數(shù)來代替:

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();
}

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

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當中即可自動執(zhí)行
run(gen);

執(zhí)行上述代碼,即可看到終端依次打印出了file1和file2的內(nèi)容。

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

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

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

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • socket.io學習教程之深入學習篇(三)

    socket.io學習教程之深入學習篇(三)

    這篇文章更加深入的給大家介紹了socket.io的相關(guān)資料,之前已經(jīng)介紹了socket.io的基本教程和應用,本文更為深入的來介紹下socket.io的使用,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-04-04
  • node 使用multer中間件上傳報錯Unexpected end of form的問題及解決方法

    node 使用multer中間件上傳報錯Unexpected end of fo

    再前幾天還是可以正常上傳,但今天運行出現(xiàn)該報錯,下面通過場景分析給大家介紹node使用multer中間件上傳,報錯Unexpected end of form的解決方案,感興趣的朋友一起看看吧
    2025-03-03
  • 一文搞懂npm?install?意義

    一文搞懂npm?install?意義

    我們在安裝依賴包的時候,不需要過多的去糾結(jié)是使用?-S?還是?-D?呢??隨便安裝到?dependencies?或者?devDependencies?里都行,反正?npm?install的時候,都會安裝dependencies?和?devDependencies依賴,今天通過本文學習npm?install意義,感興趣的朋友跟隨小編一起看看吧
    2022-12-12
  • node.js從數(shù)據(jù)庫獲取數(shù)據(jù)

    node.js從數(shù)據(jù)庫獲取數(shù)據(jù)

    這篇文章主要為大家詳細介紹了node.js從數(shù)據(jù)庫獲取數(shù)據(jù)的具體代碼,nodejs可以獲取具體某張數(shù)據(jù)表信息,感興趣的朋友可以參考一下
    2016-05-05
  • Node.js web 應用如何封裝到Docker容器中

    Node.js web 應用如何封裝到Docker容器中

    這篇文章主要介紹了Node.js web 應用如何封裝到Docker容器中,幫助大家更好的學習node.js和使用docker容器,感興趣的朋友可以了解下
    2020-09-09
  • WebSocket實現(xiàn)簡單客服聊天系統(tǒng)

    WebSocket實現(xiàn)簡單客服聊天系統(tǒng)

    這篇文章主要為大家詳細介紹了WebSocket實現(xiàn)簡單客服聊天系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 在Docker快速部署Node.js應用的詳細步驟

    在Docker快速部署Node.js應用的詳細步驟

    這篇文章的目標是為了向大家展示如何在Docker的container里運行Node.js程序,文中通過圖文與示例代碼介紹的非常詳細,有需要的朋友們可以參考借鑒。
    2016-09-09
  • windows安裝nvm并配置換源的實現(xiàn)步驟

    windows安裝nvm并配置換源的實現(xiàn)步驟

    本文介紹在Windows上安裝NVM并配置Node.js路徑和鏡像源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-11-11
  • nodejs使用PassThrough流進行數(shù)據(jù)傳遞合并示例詳解

    nodejs使用PassThrough流進行數(shù)據(jù)傳遞合并示例詳解

    這篇文章主要為大家介紹了nodejs使用PassThrough流進行數(shù)據(jù)傳遞合并示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Node.js 構(gòu)建命令行工具之實現(xiàn) ls 命令的 -a 和 -l 選項

    Node.js 構(gòu)建命令行工具之實現(xiàn) ls 命令的 -a 和 

    本文介紹了如何使用Node.js實現(xiàn)一個簡單的命令行工具,模仿常用的ls命令,包括其-a和-l參數(shù)的功能,文章詳細講解了命令行參數(shù)的解析、文件類型的判斷、權(quán)限信息的處理、文件鏈接數(shù)和修改時間的格式化等步驟,并提供了完整的代碼實現(xiàn)
    2024-11-11

最新評論

青海省| 泽库县| 渭源县| 唐河县| 南川市| 独山县| 波密县| 策勒县| 西藏| 育儿| 德江县| 高青县| 额尔古纳市| 万山特区| 玉门市| 清新县| 衡山县| 商城县| 石门县| 乌拉特后旗| 佛教| 宜阳县| 铜陵市| 多伦县| 西平县| 青河县| 海南省| 安平县| 万载县| 同心县| 晋江市| 平昌县| 贞丰县| 称多县| 车致| 太仆寺旗| 兰溪市| 象山县| 海盐县| 穆棱市| 西华县|