国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > JavaScript > 正文

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

2024-05-06 16:26:39
字體:
供稿:網(wǎng)友
這篇文章主要介紹了NodeJs并發(fā)異步的回調(diào)處理的相關(guān)資料,需要的朋友可以參考下
 

這里說并發(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)的操作。

關(guān)鍵就在兩個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方法來處理了。因為異步的關(guān)系,程序的流程有點繞,可能開始不太好理解,即使熟悉了,也有可能突然想不明白,沒關(guān)系,比如,第二個參數(shù)中的callback實際是第三個參數(shù)生成的,開始可能你就會想,這個callback倒底是啥。還有就是pending的兩個return,也是不太好理解的,需要多想想。

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

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



注:相關(guān)教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 丹凤县| 咸阳市| 阿拉善左旗| 阜城县| 湖州市| 西城区| 子洲县| 北票市| 勐海县| 广西| 怀远县| 寻乌县| 海宁市| 涡阳县| 繁峙县| 辉县市| 宿迁市| 兰坪| 眉山市| 信阳市| 新沂市| 富顺县| 芮城县| 盘锦市| 泰宁县| 揭阳市| 忻城县| 吉隆县| 甘泉县| 内丘县| 阳东县| 仙游县| 西林县| 西华县| 太仆寺旗| 永嘉县| 溧水县| 肇东市| 广饶县| 灌阳县| 灌阳县|