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

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

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

這里說并發(fā)異步,并不準確,應該說連續(xù)異步。NodeJs單線程異步的特性,直接導致多個異步同時進行時,無法確定最后的執(zhí)行結(jié)果來回調(diào)。舉個簡單的例子:

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

連續(xù)發(fā)起了5次讀文件的異步操作,很簡單,那么問題來了,我怎么確定所有異步都執(zhí)行完了呢?因為要在它們都執(zhí)行完后,才能進行之后的操作。相信有點經(jīng)驗的同學都會想到使用記數(shù)的方式來進行,但如何保證記數(shù)正確又是一個問題。仔細想想:

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

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

當pending調(diào)用時,即pending(),比如:

var done = pending(); 

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

關鍵就在兩個return上,簡單的說:

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

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

看個實際點的例子,讀取多個文件的異步回調(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í)行的方法,當計數(shù)器為0時,就會執(zhí)行它,那我們得改進一下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ù),當var done = pending(callback)時,done其實已為第一個return的函數(shù),它有一個參數(shù),可以當做返回的值的下標,所以在循環(huán)體中done(fileName[i]),把文件名傳了進去。這個done()是直接執(zhí)行的,它將count+1后,返回了要傳給異步方法的回調(diào)函數(shù),如前面所說,這個回調(diào)函數(shù)里會根據(jù)計數(shù)變量來判斷是否執(zhí)行我們希望執(zhí)行的回調(diào)函數(shù),而且把文件的內(nèi)容傳給了它,即returns。好了,運行一下,相信能夠準確的看到運行結(jié)果。

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

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

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

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

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有三個參數(shù),意思是:

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

func: 異步方法,比如fs.readFile,就是通過它傳進去的

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

done和前面同理,它傳給了func,但并沒有執(zhí)行,因為希望應用端能可控制參數(shù),所以讓應用端去執(zhí)行。

再看看處理子模板時的操作:

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這個列表,是根據(jù)對子模板的解析生成的數(shù)據(jù),它是一個二維的數(shù)組,每個子項的第一個值為子模板的調(diào)用文本,即:{% include 'header.html' %}這樣的字符串,第二個參數(shù)為子模板文件名,即:header.html

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

這樣子,只要需要連續(xù)異步時,就可以使用asyncSeries方法來處理了。因為異步的關系,程序的流程有點繞,可能開始不太好理解,即使熟悉了,也有可能突然想不明白,沒關系,比如,第二個參數(shù)中的callback實際是第三個參數(shù)生成的,開始可能你就會想,這個callback倒底是啥。還有就是pending的兩個return,也是不太好理解的,需要多想想。

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

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

相關文章

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

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

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

    淺談如何把Node項目部署到服務器上

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

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

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

    Node.js + express基本用法教程

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

    node.js安裝及HbuilderX配置詳解

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

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

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

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

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

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

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

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

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

    nodejs下打包模塊archiver詳解

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

最新評論

宜春市| 西藏| 濉溪县| 治县。| 杭州市| 道孚县| 北京市| 镇江市| 赣州市| 隆子县| 澄城县| 广灵县| 黄梅县| 普宁市| 当雄县| 长顺县| 金沙县| 大埔县| 县级市| 公安县| 金门县| 武陟县| 龙山县| 漳浦县| 乡城县| 祥云县| 凌云县| 大兴区| 广河县| 北流市| 定陶县| 瑞安市| 岫岩| 长宁县| 杂多县| 敦煌市| 郁南县| 都兰县| 手游| 通江县| 昆明市|