国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

nodejs q模塊

starsfun / 1834人閱讀

摘要:如果按照上面回調(diào)函數(shù)的寫法這種寫法看起來雖然簡(jiǎn)單,但是如果在各個(gè)任務(wù)中都含有多個(gè)復(fù)雜的邏輯操作,需要串行操作的任務(wù)一旦變多,那么這種回調(diào)的寫法就可讀性非常差,而且難以維護(hù)。

接觸nodejs時(shí)間不長(zhǎng),如果有所紕漏,請(qǐng)大家批評(píng)指正

nodejs module q

眾所周知,nodejs是異步的,但是何為異步呢?就是設(shè)置一個(gè)任務(wù)后立即返回,然后加上一個(gè)監(jiān)聽,當(dāng)任務(wù)結(jié)束的時(shí)候,就去調(diào)用監(jiān)聽。

比如下面的代碼:

fs = require("fs")
fs.readFile("/etc/hosts", "utf8", function (err,data) { // 設(shè)置了一個(gè)監(jiān)聽,文件讀取完畢以后調(diào)用
  if (err) {
    return console.log(err);
  }
  console.log(data);
}); // 不阻塞,馬上返回

console.log("starting read file...");

// result:
// starting read file...
// host file content

要是對(duì)于簡(jiǎn)單的任務(wù),這是一個(gè)非常好的設(shè)計(jì),給你一個(gè)任務(wù),任務(wù)做好了馬上告訴我,然后觸發(fā)相應(yīng)的操作

但是如果對(duì)于復(fù)雜的任務(wù),就未必是一種好的做法了。比如我們現(xiàn)在有多個(gè)任務(wù)需要進(jìn)行處理,但是這些任務(wù)之間存在以來關(guān)系,比如任務(wù)二需要在任務(wù)一完成以后才可以開始,任務(wù)三要在任務(wù)二后面才可以開始。。。如果按照上面回調(diào)函數(shù)的寫法:

task1(function (value1) {
    task2(value1, function(value2) {
        task3(value2, function(value3) {
            task4(value3, function(value4) {
                // Do something with value4
                // ... more task ...
                // I am in the callback hell
            });
        });
    });
});

這種寫法看起來雖然簡(jiǎn)單,但是如果在各個(gè)任務(wù)中都含有多個(gè)復(fù)雜的邏輯操作,需要串行操作的任務(wù)一旦變多,那么這種回調(diào)的寫法就可讀性非常差,而且難以維護(hù)。也就是所謂的回調(diào)地獄

拿有沒有什么方法可以簡(jiǎn)化這種復(fù)雜的操作呢?答案是肯定的,那就是nodejs里面的q模塊。

q模塊

q模塊不僅僅是為了解決回調(diào)地獄的問題,它還能很大程度上輔助你進(jìn)行一些需要并行,串行,定時(shí)等操作。

promise

promise是用來取代回調(diào)函數(shù)來進(jìn)行異步操作的另一種方案

我們先來看一下大牛對(duì)promise的定義

A promise is an abstraction for asynchronous programming. It’s an object that proxies for the return value or the exception thrown by a function that has to do some asynchronous processing. — Kris Kowal on JSJ

我們做什么事都不要忘了最初的目的,我們最初采用回調(diào)的目的就是布置一件任務(wù),任務(wù)結(jié)束以后,就將操作的數(shù)據(jù)傳入我們注冊(cè)的函數(shù),我們?cè)偃ヌ幚頂?shù)據(jù)。

promise做的事情也是同樣的目的,為了異步操作得到數(shù)據(jù),首先布置一件任務(wù),然后返回一個(gè)promise對(duì)象,該promise對(duì)象承諾一定給我一個(gè)結(jié)果,要是是任務(wù)成功將結(jié)果返回給我,要么就是任務(wù)執(zhí)行失敗,返回一個(gè)異常信息。

所以只要我們有這個(gè)promise對(duì)象,我們就可以在任何地方處理promise返回給我們的結(jié)果,就是這么優(yōu)雅。換句話說,就是將任務(wù)布置的代碼和任務(wù)結(jié)果的處理代碼進(jìn)行了分離。

我們來看一個(gè)例子

function myReadFile(){
    var deferred = Q.defer();
    FS.readFile("foo.txt", "utf-8", function (error, text) {
        if (error) {
            deferred.reject(new Error(error));
        } else {
            deferred.resolve(text);
        }
    });
    return deferred.promise; // 這里返回一個(gè)承諾
}
/**
* many many code here
*/
promise.then(function(data){ 
    console.log("get the data : "+data);
},function(err){
    console.err(err);
});

好啦,既然知道什么是promise了,我們就開始探討一下q模塊

q模塊的安裝

安裝nodejs

node官網(wǎng)下載安裝nodejs

新建一個(gè)工程,填寫一基本信息

mkdir qtest && cd qtest && npm init

安裝q模塊

npm install q --save

promise的使用

下面是博主在學(xué)習(xí)q模塊的時(shí)候所見所得,可能有所紕漏,如果需要q模塊的全面資料,大家可以參見這里

then 函數(shù)

我們知道,當(dāng)?shù)玫揭粋€(gè)promise以后,我們需要指定對(duì)應(yīng)的處理函數(shù),也就是用then函數(shù)來指定對(duì)應(yīng)的處理函數(shù)。

then函數(shù)傳入兩個(gè)函數(shù)對(duì)象:

當(dāng)promisefulfilled的時(shí)候執(zhí)行的函數(shù)

當(dāng)promiserejected的時(shí)候執(zhí)行的函數(shù)

每次只有一個(gè)函數(shù)可能被執(zhí)行,因?yàn)榉祷氐?b>promise只可能存在一個(gè)狀態(tài),要么被promise被解決了,要么promise沒有被解決。

最終then函數(shù)返回一個(gè)新的promise

如下面所示:

var outputPromise = getInputPromise() 
.then(function fulfilled_function(input) {// 傳入兩個(gè)函數(shù)對(duì)象,一個(gè)用來處理fulfilled情況,一個(gè)處理rejected情況
}, function fulfilled_function(reason) {
}); // 最終返回一個(gè)新的promise

在傳入的fulfilled_functionrejected_function函數(shù)中,函數(shù)的返回值會(huì)影響then函數(shù)返回的promise(也就是這里的outputPromise)的行為:

如果返回一個(gè)普通值,promise就是fulfilled

如果拋出一個(gè)異常,那么promise就是rejected

如果返回一個(gè)新的promise,那么then函數(shù)返回的promise將會(huì)被這個(gè)新的promise取代。

如果你只關(guān)心任務(wù)的成功或者失敗狀態(tài),上面的fulfilled_function或者rejected_function可以設(shè)置為空。

我們來看幾個(gè)例子:

返回一個(gè)普通值:

var Q = require("q");

var outputPromise = Q(1).then(function(data){
   console.log(data);
   return 2; // outputPromise將會(huì)fulfilled
});

outputPromise.then(function(data){
    console.log("FULFILLED : "+data);
},function(err){
    console.log("REJECTED : "+err);
})
/** 運(yùn)行結(jié)果
1
FULFILLED : 2
*/

拋出一個(gè)異常

var Q = require("q");

var outputPromise = Q(1).then(function(data){
   console.log(data);
   throw new Error("haha ,error!"); 
   return 2; 
});

outputPromise.then(function(data){
    console.log("FULFILLED : "+data);
},function(err){
    console.log("REJECTED : "+err);
})
/** 運(yùn)行結(jié)果
1
REJECTED : Error: haha ,error!
*/

返回一個(gè)新的promise

var Q = require("q");

var outputPromise = Q(1).then(function(data){
   console.log(data);
   return Q(3); 
});

outputPromise.then(function(data){
    console.log("FULFILLED : "+data);
},function(err){
    console.log("REJECTED : "+err);
})

/** 運(yùn)行結(jié)果
1
FULFILLED : 3
*/
流式操作

上面提到過then函數(shù)最后會(huì)返回一個(gè)新的promise,這樣我們就可以將多個(gè)promise串聯(lián)起來,完成一系列的串行操作。

如下面所示:

return getUsername()
.then(function (username) {
    return getUser(username);
})
.then(function (user) {
    // if we get here without an error,
    // the value returned here
    // or the exception thrown here
    // resolves the promise returned
    // by the first line
});
組合操作

假如我們現(xiàn)在有多個(gè)任務(wù)需要一起并行操作,然后所有任務(wù)操作結(jié)束后,或者其中一個(gè)任務(wù)失敗后就直接返回,q模塊的中的all函數(shù)就是用來解決這個(gè)問題的。

我們來幾個(gè)例子

成功執(zhí)行:

var Q = require("q");

function createPromise(number){
    return Q(number*number); 
}

var array = [1,2,3,4,5];

var promiseArray = array.map(function(number){
    return createPromise(number);
});

Q.all(promiseArray).then(function(results){
    console.log(results);
});

/** 運(yùn)行結(jié)果
[ 1, 4, 9, 16, 25 ]
*/

其中某個(gè)拋出異常:

var Q = require("q");

function createPromise(number){
    if(number ===3 )
        return Q(1).then(function(){
            throw new Error("haha, error!");
        })
    return Q(number*number); 
}

var array = [1,2,3,4,5];

var promiseArray = array.map(function(number){
    return createPromise(number);
});

Q.all(promiseArray).then(function(results){
    console.log(results);
},function (err) {
    console.log(err);
});
/** 運(yùn)行結(jié)果
[Error: haha, error!]
*/

但是有些時(shí)候我們想等到所有promise都得到一個(gè)結(jié)果以后,我們?cè)趯?duì)結(jié)果進(jìn)行判斷,看看那些是成功的,那些是失敗的,我們就可以使用allSettled函數(shù)。

如下所示:

var Q = require("q");

function createPromise(number){
    if(number ===3 )
        return Q(1).then(function(){
            throw new Error("haha, error!");
        })
    return Q(number*number); 
}

var array = [1,2,3,4,5];

var promiseArray = array.map(function(number){
    return createPromise(number);
});


Q.allSettled(promiseArray)
    .then(function (results) {
        results.forEach(function (result) {
            if (result.state === "fulfilled") {
                console.log(result.value);
            } else {
                console.error(result.reason);
            }
        });
    });
/** 運(yùn)行結(jié)果
1
4
[Error: haha, error!]
16
25
*/

或者有時(shí)候我們只需要其中一個(gè)promise有結(jié)果即可,那么any函數(shù)就比較適合我們

如下所示:

var Q = require("q");

function createPromise(number){
    if(number ===3 || number === 1 )
        return Q(1).then(function(){
            throw new Error("haha, error!");
        })
    return Q(number*number); 
}

var array = [1,2,3,4,5];

var promiseArray = array.map(function(number){
    return createPromise(number);
});

Q.any(promiseArray).then(function(first){
    console.log(first);
},function(error){
    console.log(error); // all the promises were rejected
});

/** 運(yùn)行結(jié)果
4
*/
Promise的創(chuàng)建

上面我們講到的都是promise的使用,那么如何創(chuàng)建一個(gè)新的promise呢,q模塊里面提供好幾種方法來創(chuàng)建一個(gè)新的promise

Using Q.fcall

Using Deferreds

Using Q.promise

Using Q.fcall

你可以使用fcall來直接創(chuàng)建一個(gè)將會(huì)fullfilledpromise

return Q.fcall(function () {
    return 10;
});

也可以創(chuàng)建一個(gè)將會(huì)rejectedpromise

return Q.fcall(function () {
    throw new Error("Can"t do it");
});

或者才創(chuàng)建一個(gè)promise的時(shí)候傳入自定義參數(shù):

return Q.fcall(function(number1 , number2){
    return number1+number2;
}, 2, 2);
Using Deferreds

上面我們提到的fcall方法來創(chuàng)建promise的方法,雖然簡(jiǎn)單,但是在某些時(shí)候不一定能滿足我們的需求,比如我們現(xiàn)在創(chuàng)建一個(gè)新的promise,需要在某個(gè)任務(wù)完成以后,讓promise變成fulfilled或者是rejected狀態(tài)的,上面的fcall方法就不適合了,因?yàn)樗侵苯臃祷氐摹?/p>

那么這里使用Deferred來實(shí)現(xiàn)這種操作就再合適不過了,我們首先創(chuàng)建一個(gè)promise,然后在合適的時(shí)候?qū)?b>promise設(shè)置成為fulfilled或者rejected狀態(tài)的。

如下所示:

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
    if (error) {
        deferred.reject(new Error(error));
    } else {
        deferred.resolve(text);
    }
});
return deferred.promise;
Using Q.Promise

最后一個(gè)要介紹的就是Q.Promise函數(shù),這個(gè)方法其實(shí)是和Deferred方法比較類似的,我們要傳入一個(gè)帶有三個(gè)參數(shù)的函數(shù)對(duì)象,分別是resolve,reject,notify。可以調(diào)用這三個(gè)函數(shù)來設(shè)置promise的狀態(tài)。

看個(gè)例子:

var Q = require("q");
var request = require("request");

function requestUrl(url) {
    return Q.Promise(function(resolve, reject, notify) {
        request(url, function (error, response, body) {
            if(error)
                reject(error);
            if (!error && response.statusCode == 200) {
                resolve(body);
            }
        })
    });
}

requestUrl("http://www.baidu.com").then(function(data){
    console.log(data);
},function(err){
    console.error(err);
});
/** 運(yùn)行結(jié)果
百度首頁html內(nèi)容
*/
實(shí)際例子

這里我們將會(huì)模擬串行和并行請(qǐng)求多個(gè)url地址。

測(cè)試服務(wù)器

我在本地搭建了一個(gè)測(cè)試用的express服務(wù)器:,對(duì)應(yīng)代碼如下

var express = require("express");
var router = express.Router();

/* GET home page. */
router.get("/address1", function(req, res, next) {
    res.send("This is address1");
});

router.get("/address2", function(req, res, next) {
    res.send("This is address2");
});

router.get("/address3", function(req, res, next) {
    res.send("This is address3");
});

module.exports = router;
并行請(qǐng)求
var Q = require("q");
var request = require("request");

var urls = [
    "http://localhost:3014/q-test/address1",
    "http//localhost:3014/q-test/address2", // this is wrong address
    "http://localhost:3014/q-test/address3"
];

function createPromise(url){
    var deferred = Q.defer();
    request(url , function(err , response , body){
        console.log("requested "+url);
        if(err)
            deferred.reject(err);
        else
            deferred.resolve(body);
    });
    return deferred.promise;
}

var promises = urls.map(function (url) {
    return createPromise(url) ;
});


Q.allSettled(promises) .then(function (results) {
    results.forEach(function (result) {
        if (result.state === "fulfilled") {
            console.log(result.value);
        } else {
            console.error(result.reason);
        }
    });
});
/** 運(yùn)行結(jié)果
requested http//localhost:3014/q-test/address2
requested http://localhost:3014/q-test/address1
requested http://localhost:3014/q-test/address3
This is address1
[Error: Invalid URI "http//localhost:3014/q-test/address2"]
This is address3
*/
串行請(qǐng)求
var Q = require("q");
var request = require("request");

var urls = [
    "http://localhost:3014/q-test/address1",
    "http//localhost:3014/q-test/address2", // this is wrong address
    "http://localhost:3014/q-test/address3",
    "done" // append a useless item
];

function createPromise(url){
    var deferred = Q.defer();
    request(url , function(err , response , body){
        if(err)
            deferred.reject(err);
        else
            deferred.resolve(body);
    });
    return deferred.promise;
}


urls.reduce(function(soFar , url){
   return soFar.then(function(data){
       if(data)
           console.log(data);
       return createPromise(url);
   } ,function(err){
       console.error(err);
       return createPromise(url);
   }) 
},Q(null));
/** 運(yùn)行結(jié)果
requested http://localhost:3014/q-test/address1
This is address1
requested http//localhost:3014/q-test/address2
[Error: Invalid URI "http//localhost:3014/q-test/address2"]
requested http://localhost:3014/q-test/address3
This is address3
requested done
*/
延時(shí)操作

下面我們使用q模塊來對(duì)express服務(wù)器進(jìn)行延時(shí)操作:

var express = require("express");
var router = express.Router();
var Q = require("q");

function myDelay(ms){ // 定義延時(shí)操作,返回promise
    var deferred = Q.defer() ;
    setTimeout(deferred.resolve , ms);
    return deferred.promise;
}

/* GET home page. */
router.get("/address1", function(req, res, next) {
    myDelay(5000).then(function(){
        res.send("This is address1"); // 時(shí)間到了就返回?cái)?shù)據(jù)
    });
});

router.get("/address2", function(req, res, next) {
    res.send("This is address2");
});

router.get("/address3", function(req, res, next) {
    res.send("This is address3");
});

module.exports = router;

好,上面的串行和并行操作我們并沒有看出什么區(qū)別,現(xiàn)在我們?cè)賮砼芤槐槌绦?

并行結(jié)果

/** 運(yùn)行結(jié)果
requested http//localhost:3014/q-test/address2
requested http://localhost:3014/q-test/address3
requested http://localhost:3014/q-test/address1
This is address1
[Error: Invalid URI "http//localhost:3014/q-test/address2"]
This is address3
*/

串行結(jié)果

/** 運(yùn)行結(jié)果
requested http://localhost:3014/q-test/address1
This is address1
requested http//localhost:3014/q-test/address2
[Error: Invalid URI "http//localhost:3014/q-test/address2"]
requested http://localhost:3014/q-test/address3
This is address3
requested done
*/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79461.html

相關(guān)文章

  • 基于nodejs編寫小爬蟲

    摘要:編寫異步小爬蟲在通過的課程初步了解的各大模塊之后,不禁感慨于的強(qiáng)大,讓我們這些前端小白也可以進(jìn)行進(jìn)階的功能實(shí)現(xiàn),同時(shí)發(fā)現(xiàn)自己也已經(jīng)可以通過實(shí)現(xiàn)一些比較日常的小功能。 nodejs編寫異步小爬蟲 在通過learnyounode的課程初步了解nodejs的各大模塊之后,不禁感慨于nodejs的強(qiáng)大,讓我們這些前端小白也可以進(jìn)行進(jìn)階的功能實(shí)現(xiàn),同時(shí)發(fā)現(xiàn)自己也已經(jīng)可以通過nodejs實(shí)現(xiàn)一些...

    3fuyu 評(píng)論0 收藏0
  • Gulp使用入門

    摘要:是一款流式構(gòu)建系統(tǒng),如果說是基于任務(wù)執(zhí)行器,就是基于的文件流任務(wù)執(zhí)行器,比起有如下特點(diǎn)使用方便通過代碼優(yōu)于配置的策略,可以讓簡(jiǎn)單的任務(wù)簡(jiǎn)單,復(fù)雜的任務(wù)更可管理。 作者:Jogis原文鏈接:https://github.com/yesvods/Blog/issues/1轉(zhuǎn)載請(qǐng)注明原文鏈接以及作者信息 showImg(http://itanguo.cn/wp-content/uploads...

    ShevaKuilin 評(píng)論0 收藏0
  • node.js中文資料導(dǎo)航

    摘要:中文資料導(dǎo)航官網(wǎng)七牛鏡像深入淺出系列進(jìn)階必讀中文文檔被誤解的編寫實(shí)戰(zhàn)系列熱門模塊排行榜,方便找出你想要的模塊多線程,真正的非阻塞淺析的類利用編寫異步多線程的實(shí)例中與的區(qū)別管道拒絕服務(wù)漏洞高級(jí)編程業(yè)界新聞看如何評(píng)價(jià)他們的首次嘗鮮程序員如何說服 node.js中文資料導(dǎo)航 Node.js HomePage Node官網(wǎng)七牛鏡像 Infoq深入淺出Node.js系列(進(jìn)階必讀) Nod...

    geekidentity 評(píng)論0 收藏0
  • nodejs微服務(wù)解決方案

    摘要:前言是一個(gè)微服務(wù)工具集,它賦予系統(tǒng)易于連續(xù)構(gòu)建和更新的能力。這個(gè)對(duì)象既包含某個(gè)微服務(wù)所需要調(diào)取另一個(gè)微服務(wù)的特征,同時(shí)也包含傳參。和微服務(wù)發(fā)現(xiàn)有些類似不過是用模式代替,目前為止模式是完全可以實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)功能,但是否更加靈活還有待去挖掘。 前言 seneca是一個(gè)nodejs微服務(wù)工具集,它賦予系統(tǒng)易于連續(xù)構(gòu)建和更新的能力。下面會(huì)逐一和大家一起了解相關(guān)技術(shù)入門以及實(shí)踐。 這里插入一段硬廣...

    canger 評(píng)論0 收藏0
  • 公司項(xiàng)目NODEJS實(shí)踐0.1[ ubuntu,nodejs,nginx...]

    摘要:創(chuàng)建成功后進(jìn)入文件夾執(zhí)行執(zhí)行作用創(chuàng)建文件,維護(hù)項(xiàng)目的依賴文件解釋創(chuàng)建文件執(zhí)行作用用系統(tǒng)的編輯器打開文件。我的技術(shù)新群上一篇前后端分離項(xiàng)目實(shí)踐分析下一篇公司項(xiàng)目實(shí)踐 一、前言 前端如何獨(dú)立用nodeJs實(shí)現(xiàn)一個(gè)簡(jiǎn)單的注冊(cè)、登錄功能,是不是只用nodejs+sql就可以了?其實(shí)是可以實(shí)現(xiàn),但離實(shí)際應(yīng)用還有距離,那要怎么做才是實(shí)際可用的。 網(wǎng)上有很多nodeJs的示例,包括和 sql /...

    cppprimer 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<