nodejs解決回調(diào)地獄

1.async

https://github.com/caolan/async/blob/v1.5.2/README.md#times
https://github.com/bsspirit/async_demo 一些demo

var mysql = require('mysql');
var conn = mysql.createConnection({
    host: 'localhost',
    user: 'nodejs',
    password: 'nodejs',
    database: 'nodejs',
    port: 3306
});
conn.connect();

var insertSQL = 'insert into t_user(name) values("conan"),("fens.me")';
var selectSQL = 'select * from t_user limit 10';
var deleteSQL = 'delete from t_user';
var updateSQL = 'update t_user set name="conan update"  where name="conan"';

//delete
conn.query(deleteSQL, function (err0, res0) {
    if (err0) console.log(err0);
    console.log("DELETE Return ==> ");
    console.log(res0);

    //insert
    conn.query(insertSQL, function (err1, res1) {
        if (err1) console.log(err1);
        console.log("INSERT Return ==> ");
        console.log(res1);

        //query
        conn.query(selectSQL, function (err2, rows) {
            if (err2) console.log(err2);

            console.log("SELECT ==> ");
            for (var i in rows) {
                console.log(rows[i]);
            }

            //update
            conn.query(updateSQL, function (err3, res3) {
                if (err3) console.log(err3);
                console.log("UPDATE Return ==> ");
                console.log(res3);

                //query
                conn.query(selectSQL, function (err4, rows2) {
                    if (err4) console.log(err4);

                    console.log("SELECT ==> ");
                    for (var i in rows2) {
                        console.log(rows2[i]);
                    }
                });
            });
        });
    });
});

//conn.end();

//改進(jìn)

var mysql = require('mysql');
var async = require('async');

var conn = mysql.createConnection({
    host: 'localhost',
    user: 'nodejs',
    password: 'nodejs',
    database: 'nodejs',
    port: 3306
});

var sqls = {
    'insertSQL': 'insert into t_user(name) values("conan"),("fens.me")',
    'selectSQL': 'select * from t_user limit 10',
    'deleteSQL': 'delete from t_user',
    'updateSQL': 'update t_user set name="conan update"  where name="conan"'
};

var tasks = ['deleteSQL', 'insertSQL', 'selectSQL', 'updateSQL', 'selectSQL'];
async.eachSeries(tasks, function (item, callback) {
    console.log(item + " ==> " + sqls[item]);
    conn.query(sqls[item], function (err, res) {
        console.log(res);
        callback(err, res);
    });
}, function (err) {
    console.log("err: " + err);
});

1. series(tasks, [callback]) (多個(gè)函數(shù)依次執(zhí)行,之間沒(méi)有數(shù)據(jù)交換)

解決問(wèn)題

step1(function(err, v1) {
     step2(function(err, v2) { 
        step3(function(err, v3) { // do somethig with the err or values v1/v2/v3 
        } 
     }
});
var async = require('async')
async.series([
  function(cb) { step1(function(err,v1) {
     // do something with v1
     cb(err, v1);
  }),
  function(cb) { step2(...) },
  function(cb) { step3(...) }
], function(err, values) {
// do somethig with the err or values v1/v2/v3
});

2. parallel(tasks, [callback]) (多個(gè)函數(shù)并行執(zhí)行)

如果某個(gè)函數(shù)出錯(cuò),則立刻將err和已經(jīng)執(zhí)行完的函數(shù)的結(jié)果值傳給parallel最終的callback。其它未執(zhí)行完的函數(shù)的值不會(huì)傳到最終數(shù)據(jù),但要占個(gè)位置距境。
同時(shí)支持json形式的tasks,其最終callback的結(jié)果也為json形式恼布。
示例代碼:

async.parallel([
    function(cb) { t.fire('a400', cb, 400) },
    function(cb) { t.fire('a200', cb, 200) },
    function(cb) { t.fire('a300', cb, 300) }
], function (err, results) {
    log('1.1 err: ', err); // -> undefined
    log('1.1 results: ', results); // ->[ 'a400', 'a200', 'a300' ]
});
async.parallel([
    function(cb) { log('1.2.1: ', 'start'); t.fire('a400', cb, 400) }, // 該函數(shù)的值不會(huì)傳給最終callback耳贬,但要占個(gè)位置
    function(cb) { log('1.2.2: ', 'start'); t.err('e200', cb, 200) },
    function(cb) { log('1.2.3: ', 'start'); t.fire('a100', cb, 100) }
], function(err, results) {
    log('1.2 err: ', err); // -> e200
    log('1.2 results: ', results); // -> [ , undefined, 'a100' ]
});

3. waterfall(tasks, [callback]) (多個(gè)函數(shù)依次執(zhí)行,且前一個(gè)的輸出為后一個(gè)的輸入)

seires相似醋旦,按順序依次執(zhí)行多個(gè)函數(shù)恒水。不同之處,每一個(gè)函數(shù)產(chǎn)生的值饲齐,都將傳給下一個(gè)函數(shù)钉凌。如果中途出錯(cuò),后面的函數(shù)將不會(huì)被執(zhí)行捂人。錯(cuò)誤信息以及之前產(chǎn)生的結(jié)果御雕,將傳給waterfall最終的callback。

async.waterfall([
    function(cb) { log('1.1.1: ', 'start'); cb(null, 3); },
    function(n, cb) { log('1.1.2: ',n); t.inc(n, cb); },
    function(n, cb) { log('1.1.3: ',n); t.fire(n*n, cb); }
], function (err, result) {
    log('1.1 err: ', err); // -> null
    log('1.1 result: ', result); // -> 16
});

二滥搭、promise解決

fs.readFile("test.txt",function(err,data){
    if(!err){
        console.log(data);
    }else{
        console.error(err);
    }
});

我們可以把 fs.readFile函數(shù)封裝為 promise風(fēng)格的函數(shù)酸纲,如下:

var preadFile = function(file){
  fs.readFile(file,function(err,data){
    var deferred = Q.defer();
    if(!err){
      deferred.resolve(data);
    }else{
      deferred.reject(err);
    }

    return deferred.promise;
  });
}
//then 的第一個(gè)參數(shù)是正確處理函數(shù),第二個(gè)參數(shù)是錯(cuò)誤處理函數(shù)
preadFile("test.txt").then(console.log,console.error);

1.各個(gè)回調(diào)函數(shù)順序傳遞數(shù)據(jù):

var fun1 = function (data,cb) {
  cb(null,data+" fun1");
}

var fun2 = function (data,cb) {
  cb(null,data+" fun2");
}

var fun3 = function (data,cb) {
  cb(null,data+" fun3");
}

function main(data,cb){
  fun1(data,function(err,data){
    if(!err){
      fun2(data,function(err,data){
        if(!err){
          fun3(data,cb);
        }else{
          cb(err);
        }
      });
    }else{
      cb(err);
    }
  });
}
var fun1 = function (data,cb) {
  cb(null,data+" fun1");
}

var fun2 = function (data,cb) {
  cb(null,data+" fun2");
}

var fun3 = function (data,cb) {
  cb(null,data+" fun3");
}

function main(data,cb){
  fun1(data,function(err,data){
    if(!err){
      fun2(data,function(err,data){
        if(!err){
          fun3(data,cb);
        }else{
          cb(err);
        }
      });
    }else{
      cb(err);
    }
  });
}

解決方法

var Q = require("q");
var fun1 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun1");
  return deferred.promise;
}

var fun2 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun2");
  return deferred.promise;
}

var fun3 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun3");
  return deferred.promise;
}

function main(data,cb){
   fun2("test")
     .then(fun3)
     .then(fun4)
     .done(function(data){
       cb(null,data);//ok 獲得的最終數(shù)據(jù)為 --->"test fun1 fun2 fun3"
     },function(err){
       cb(err);//failed
     });
}

2.收集各個(gè)回調(diào)函數(shù)產(chǎn)生的數(shù)據(jù):有時(shí)候我們需要執(zhí)行很多回調(diào)函數(shù)瑟匆,然手把這個(gè)回調(diào)函數(shù)的數(shù)據(jù)一齊傳遞給一個(gè)函數(shù)處理闽坡,此時(shí)我們可以使用 all 和 spread 方法,參看如下代碼:

var Q = require("q");
var fun1 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun1");
  return deferred.promise;
}

var fun2 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun2");
  return deferred.promise;
}

var fun3 = function (data) {
  var deferred = Q.defer();
  deferred.resolve(data+" fun3");
  return deferred.promise;
}

Q.all([
  fun2("test1"),fun3("test2"),fun4("test3")
  ]).spread(function(){
    console.log(arguments);//獲得的參數(shù)為('test1 fun1', 'test2 fun2', 'test3 fun3' )
  });

3.統(tǒng)一處理錯(cuò)誤:傳統(tǒng)的回調(diào)函數(shù)方式使用的話愁溜,我們需要在每一個(gè)回調(diào)函數(shù)里判斷是否有錯(cuò)誤需要處理疾嗅,這樣會(huì)存在很多冗余代碼,使用 promise冕象,可以使用 done 或者 fail在一個(gè)函數(shù)中處理錯(cuò)誤代承,如第一個(gè)例子一樣,使用 done 方法的第二個(gè)參數(shù)處理錯(cuò)誤渐扮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末次泽,一起剝皮案震驚了整個(gè)濱河市穿仪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌意荤,老刑警劉巖啊片,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異玖像,居然都是意外死亡紫谷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)捐寥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)笤昨,“玉大人,你說(shuō)我怎么就攤上這事握恳÷髦希” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵乡洼,是天一觀的道長(zhǎng)崇裁。 經(jīng)常有香客問(wèn)我,道長(zhǎng)束昵,這世上最難降的妖魔是什么拔稳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮锹雏,結(jié)果婚禮上巴比,老公的妹妹穿的比我還像新娘。我一直安慰自己礁遵,他們只是感情好轻绞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著佣耐,像睡著了一般政勃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晰赞,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天稼病,我揣著相機(jī)與錄音,去河邊找鬼掖鱼。 笑死然走,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的戏挡。 我是一名探鬼主播芍瑞,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褐墅!你這毒婦竟也來(lái)了拆檬?” 一聲冷哼從身側(cè)響起洪己,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竟贯,沒(méi)想到半個(gè)月后答捕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屑那,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年拱镐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片持际。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沃琅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜘欲,到底是詐尸還是另有隱情益眉,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布姥份,位于F島的核電站郭脂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏殿衰。R本人自食惡果不足惜朱庆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一盛泡、第九天 我趴在偏房一處隱蔽的房頂上張望闷祥。 院中可真熱鬧,春花似錦傲诵、人聲如沸凯砍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悟衩。三九已至,卻和暖如春栓拜,著一層夾襖步出監(jiān)牢的瞬間座泳,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工幕与, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挑势,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓啦鸣,卻偏偏與公主長(zhǎng)得像潮饱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诫给,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 本文主要講解async的函數(shù): series香拉,parallel啦扬, waterfall 函數(shù)的理解和 使用 asyn...
    吧啦啦小湯圓閱讀 1,883評(píng)論 3 2
  • 你不知道JS:異步 第三章:Promises 接上篇3-1 錯(cuò)誤處理(Error Handling) 在異步編程中...
    purple_force閱讀 1,398評(píng)論 0 2
  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop凫碌。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,711評(píng)論 0 5
  • 異步編程對(duì)JavaScript語(yǔ)言太重要扑毡。Javascript語(yǔ)言的執(zhí)行環(huán)境是“單線程”的,如果沒(méi)有異步編程盛险,根本...
    呼呼哥閱讀 7,311評(píng)論 5 22
  • 組建一個(gè)梅花島 在島上成立個(gè)菜園子 我出售善良 也出售美好 我用慈悲之心 招攬那些向上的人群 我不用大聲喧嘩 只用...
    梅花島上的菜園子閱讀 233評(píng)論 0 0