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

深入淺析NodeJs并發(fā)異步的回調(diào)處理

 更新時(shí)間:2015年12月21日 09:29:47   作者:onlyfu  
這篇文章主要介紹了NodeJs并發(fā)異步的回調(diào)處理的相關(guān)資料,需要的朋友可以參考下

這里說(shuō)并發(fā)異步,并不準(zhǔn)確,應(yīng)該說(shuō)連續(xù)異步。NodeJs單線程異步的特性,直接導(dǎo)致多個(gè)異步同時(shí)進(jìn)行時(shí),無(wú)法確定最后的執(zhí)行結(jié)果來(lái)回調(diào)。舉個(gè)簡(jiǎn)單的例子:

for(var i = 0; i < 5; i++) {
  fs.readFile('file', 'utf-8', function(error, data){});
} 

連續(xù)發(fā)起了5次讀文件的異步操作,很簡(jiǎn)單,那么問(wèn)題來(lái)了,我怎么確定所有異步都執(zhí)行完了呢?因?yàn)橐谒鼈兌紙?zhí)行完后,才能進(jìn)行之后的操作。相信有點(diǎn)經(jīng)驗(yàn)的同學(xué)都會(huì)想到使用記數(shù)的方式來(lái)進(jìn)行,但如何保證記數(shù)正確又是一個(gè)問(wèn)題。仔細(xì)想想:

回調(diào)是一個(gè)函數(shù),每個(gè)異步操作時(shí)將計(jì)數(shù)器+1,當(dāng)每個(gè)異步結(jié)束時(shí)將計(jì)數(shù)器-1,通過(guò)判斷計(jì)數(shù)器是否為0來(lái)確定是否執(zhí)行回調(diào)。這個(gè)邏輯很簡(jiǎn)單,需要一個(gè)相對(duì)于執(zhí)行時(shí)和回調(diào)時(shí)的全局變量作為計(jì)數(shù)器,而且要在傳給異步方法是執(zhí)行+1的操作,而且之后將返回一個(gè)用來(lái)回調(diào)的函數(shù),有點(diǎn)繞,不過(guò)看看Js函數(shù)的高級(jí)用法:

var pending = (function() {
  var count = 0;
  return function() {
    count++;
    return function() {
      count--;
      if (count === 0) {
        // 全部執(zhí)行完畢
      }
    }
  }
}); 

當(dāng)pending調(diào)用時(shí),即pending(),比如:

var done = pending(); 

這時(shí)計(jì)數(shù)變量count即被初始化為0,返回的函數(shù)附給了done,這時(shí)如果執(zhí)行done(),會(huì)是什么?是不是直接執(zhí)行pending返回的第一個(gè)函數(shù),即:pending()(),這個(gè)執(zhí)行又是什么,首先將計(jì)數(shù)變量count+1,又返回了一個(gè)函數(shù),這個(gè)函數(shù)直接當(dāng)做callback傳給異步的方法,當(dāng)執(zhí)行這個(gè)callback的時(shí)候,首先是將計(jì)數(shù)變量count-1,再判斷count是否為0,如果為0即表示所有的異步執(zhí)行完成了,從而達(dá)到連續(xù)的異步,同一回調(diào)的操作。

關(guān)鍵就在兩個(gè)return上,簡(jiǎn)單的說(shuō):

第一個(gè)return的函數(shù)是將count+1,接著返回需要回調(diào)的函數(shù)

第二個(gè)return的函數(shù)就是需要回調(diào)的函數(shù),如果它執(zhí)行,就是將count-1,然后判斷異步是否全部執(zhí)行完成,完成了,就回調(diào)

看個(gè)實(shí)際點(diǎn)的例子,讀取多個(gè)文件的異步回調(diào):

var fileName = ['1.html', '2.html', '3.html'];
var done = pending(function(fileData) {
  console.log('done');
  console.log(fielData);
});
for(var i = 0; i < fileName.lenght; i++) {
  fs.readFile(fileName[i], 'utf-8', done(fileName[i]));
}

其中的done,即用pending方法包起了我們想回調(diào)執(zhí)行的方法,當(dāng)計(jì)數(shù)器為0時(shí),就會(huì)執(zhí)行它,那我們得改進(jìn)一下pending方法:

var pending = (function(callback) {
  var count = 0;
  var returns = {};
  console.log(count);
  return function(key) {
    count++;
    console.log(count);
    return function(error, data) {
      count--;
      console.log(count);
      returns[key] = data;
      if (count === 0) {
        callback(returns);
      }
    }
  }
}); 

callback即為我們的回調(diào)函數(shù),當(dāng)var done = pending(callback)時(shí),done其實(shí)已為第一個(gè)return的函數(shù),它有一個(gè)參數(shù),可以當(dāng)做返回的值的下標(biāo),所以在循環(huán)體中done(fileName[i]),把文件名傳了進(jìn)去。這個(gè)done()是直接執(zhí)行的,它將count+1后,返回了要傳給異步方法的回調(diào)函數(shù),如前面所說(shuō),這個(gè)回調(diào)函數(shù)里會(huì)根據(jù)計(jì)數(shù)變量來(lái)判斷是否執(zhí)行我們希望執(zhí)行的回調(diào)函數(shù),而且把文件的內(nèi)容傳給了它,即returns。好了,運(yùn)行一下,相信能夠準(zhǔn)確的看到運(yùn)行結(jié)果。

0
1
2
3
2
1
0
done
{"1.html": "xxx", "2.html": "xxx", "3.html": "xxx"}

從計(jì)數(shù)上明顯能看出,從0-3再到0,之后就是我們的回調(diào)函數(shù)輸出了done和文件的內(nèi)容。

這個(gè)問(wèn)題解決了,我們要思考一下,如何讓這樣的方法封裝重用,不然,每次都寫pending不是很不科學(xué)嗎?

下面看看UnJs(我的一個(gè)基于NodeJs的Web開(kāi)發(fā)框架)的處理方式,應(yīng)用于模板解析中的子模板操作:

unjs.asyncSeries = function(task, func, callback) {
  var taskLen = task.length;
  if (taskLen <= 0) {
    return;
  }
  var done = unjs.pending(callback);
  for(var i = 0; i < taskLen; i++) {
    func(task[i], done);
  }
} 

asyncSeries有三個(gè)參數(shù),意思是:

task: 需要處理的對(duì)象,比如需要讀取的文件,它是一個(gè)列表,如果不是列表,或列表長(zhǎng)度為0,它將不會(huì)執(zhí)行

func: 異步方法,比如fs.readFile,就是通過(guò)它傳進(jìn)去的

callback: 我們希望回調(diào)的方法

done和前面同理,它傳給了func,但并沒(méi)有執(zhí)行,因?yàn)橄M麘?yīng)用端能可控制參數(shù),所以讓應(yīng)用端去執(zhí)行。

再看看處理子模板時(shí)的操作:

var subTemplate = [];
var patt = /\{\% include \'(.+)\' \%\}/ig;
while(sub = patt.exec(data)) {
  var subs = sub;
  subTemplate.push([subs[0], subs[1]]);
}
unjs.asyncSeries(subTemplate, function(item, callback) {
  fs.readFile('./template/' + item[1], 'utf-8', callback(item[0]));
}, function(data) {
  for(var key in data) {
    html = html.replace(key, data[key]);
  }
}); 

subTemplate這個(gè)列表,是根據(jù)對(duì)子模板的解析生成的數(shù)據(jù),它是一個(gè)二維的數(shù)組,每個(gè)子項(xiàng)的第一個(gè)值為子模板的調(diào)用文本,即:{% include 'header.html' %}這樣的字符串,第二個(gè)參數(shù)為子模板文件名,即:header.html

asyncSeries的第二個(gè)參數(shù)是的callback,實(shí)際上是第三個(gè)參數(shù),也就是我們希望執(zhí)行的回調(diào)函數(shù)經(jīng)過(guò)pending處理的回調(diào)方法,如前面所說(shuō),在asyncSeries內(nèi)部,它并沒(méi)有運(yùn)行,而是到這里運(yùn)行的,即:callback(item[0]),帶上了參數(shù),因?yàn)楹竺孢€要根據(jù)這個(gè)參數(shù)將父模板中調(diào)用子模板的字符串替換為對(duì)應(yīng)子模板的內(nèi)容。

這樣子,只要需要連續(xù)異步時(shí),就可以使用asyncSeries方法來(lái)處理了。因?yàn)楫惒降年P(guān)系,程序的流程有點(diǎn)繞,可能開(kāi)始不太好理解,即使熟悉了,也有可能突然想不明白,沒(méi)關(guān)系,比如,第二個(gè)參數(shù)中的callback實(shí)際是第三個(gè)參數(shù)生成的,開(kāi)始可能你就會(huì)想,這個(gè)callback倒底是啥。還有就是pending的兩個(gè)return,也是不太好理解的,需要多想想。

好了,連續(xù)異步的回調(diào)使用Js函數(shù)的高級(jí)特性完成了。但NodeJs的異步性著實(shí)讓程序的控制很成問(wèn)題,諸如還有連續(xù)異步,但要傳值的操作等,這些都是可以通過(guò)這樣的思路,變化一下即可實(shí)現(xiàn)的。

以上內(nèi)容是小編給大家分享的NodeJs并發(fā)異步的回調(diào)處理的相關(guān)知識(shí),希望大家喜歡。

相關(guān)文章

  • 詳解如何實(shí)現(xiàn)自由切換Node.js版本

    詳解如何實(shí)現(xiàn)自由切換Node.js版本

    作為開(kāi)發(fā)者,我們經(jīng)常在不同的項(xiàng)目中需要使用不同版本的 Node.js,有時(shí)舊項(xiàng)目需要舊版本,而新項(xiàng)目則可能依賴最新的 Node.js 版本,本文將介紹幾種常用的方法來(lái)自由切換 Node.js 版本,需要的朋友可以參考下
    2024-10-10
  • 淺談如何把Node項(xiàng)目部署到服務(wù)器上

    淺談如何把Node項(xiàng)目部署到服務(wù)器上

    本文主要介紹了淺談如何把Node項(xiàng)目部署到服務(wù)器上,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Nest.js使用multer實(shí)現(xiàn)文件上傳功能

    Nest.js使用multer實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了Nest.js鵝湖使用multer實(shí)現(xiàn)文件上傳功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • Node.js + express基本用法教程

    Node.js + express基本用法教程

    這篇文章主要介紹了Node.js + express基本用法,結(jié)合實(shí)例形式分析了nodejs導(dǎo)入express、路由訪問(wèn)、數(shù)據(jù)處理等相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • node.js安裝及HbuilderX配置詳解

    node.js安裝及HbuilderX配置詳解

    這篇文章主要介紹了node.js安裝及HbuilderX配置的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • nodejs中轉(zhuǎn)換URL字符串與查詢字符串詳解

    nodejs中轉(zhuǎn)換URL字符串與查詢字符串詳解

    這篇文章主要介紹了nodejs中轉(zhuǎn)換URL字符串與查詢字符串詳解,需要的朋友可以參考下
    2014-11-11
  • Node.js使用多進(jìn)程提高任務(wù)執(zhí)行效率

    Node.js使用多進(jìn)程提高任務(wù)執(zhí)行效率

    在Node.JS中使用多進(jìn)程非常簡(jiǎn)單,合理使用多進(jìn)程,可以解放硬件的能力,讓軟件的運(yùn)行效率得到肉眼可見(jiàn)的提升。本文詳細(xì)講解了Node.js使用多進(jìn)程提高任務(wù)執(zhí)行效率的方法,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 使用node.js實(shí)現(xiàn)接口步驟詳細(xì)記錄

    使用node.js實(shí)現(xiàn)接口步驟詳細(xì)記錄

    這篇文章主要給大家介紹了關(guān)于使用node.js實(shí)現(xiàn)接口步驟的相關(guān)資料,對(duì)于剛開(kāi)始不會(huì)node寫接口和調(diào)用接口,可以通過(guò)這個(gè)清晰的初步了解到整個(gè)過(guò)程,下面需要的朋友可以參考下
    2023-03-03
  • 利用node.js開(kāi)發(fā)cli的完整步驟

    利用node.js開(kāi)發(fā)cli的完整步驟

    這篇文章主要給大家介紹了關(guān)于如何利用node.js開(kāi)發(fā)cli的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • nodejs下打包模塊archiver詳解

    nodejs下打包模塊archiver詳解

    這篇文章主要介紹了nodejs下打包模塊archiver的使用方法,非常簡(jiǎn)單實(shí)用,這里推薦給有需要的小伙伴。
    2014-12-12

最新評(píng)論

白沙| 山丹县| 蛟河市| 岗巴县| 两当县| 乌拉特中旗| 安阳市| 东丽区| 舟曲县| 电白县| 永川市| 汉寿县| 永新县| 马鞍山市| 枞阳县| 灯塔市| 缙云县| 东港市| 武山县| 藁城市| 调兵山市| 翁源县| 衡南县| 扶余县| 宜宾市| 颍上县| 克山县| 巨野县| 工布江达县| 东台市| 太仆寺旗| 安溪县| 电白县| 湖北省| 南召县| 福海县| 漳平市| 定结县| 铜川市| 乌鲁木齐县| 于田县|