node_redis 中文文档及node_redis 注释笔记(中文版)
node_redis 中文文檔及node_redis 注釋筆記(中文版)
https://github.com/NodeRedis/node_redis
redis - a node.js redis client
這是node.js的一個完整且功能豐富的Redis客戶端。它支持所有的Redis命令,并專注于高性能。
Install with:
npminstallredis
Usage Example
varredis=require("redis"),
client=redis.createClient();
//ifyou'dliketoselectdatabase3,insteadof0(default),call
//client.select(3,function(){/*...*/});
client.on("error",function(err){
console.log("Error"+err);
});
client.set("stringkey","stringval",redis.print);
client.hset("hashkey","hashtest1","somevalue",redis.print);
client.hset(["hashkey","hashtest2","someothervalue"],redis.print);
client.hkeys("hashkey",function(err,replies){
console.log(replies.length+"replies:");
replies.forEach(function(reply,i){
console.log(""+i+":"+reply);
});
client.quit();
});
This will display:
mjr:~/work/node_redis(master)$nodeexample.js Reply:OK Reply:0 Reply:0 2replies: 0:hashtest1 1:hashtest2 mjr:~/work/node_redis(master)$
請注意,該API完全是異步的。您需要使用一個回調,從服務器獲取數據。自從2.6版本開始,API支持在所有地方的選項、變量、事件等等使用駝峰和下劃線命名規范。不過,建議使用Node.js默認的風格——駝峰式。
--------------------------------------------------
譯者注:
關于異步我做了一個如下demo
varredis=require("redis"),
client=redis.createClient();
client.set("stringkey",true,()=>{
console.log(1)
});
console.log(2)
client.get("stringkey",(err,key)=>{
console.log(3)
});
console.log(4)
返回了
2 4 1 3
--------------------------------------------------
Promises
你也可以通過如下方式使用bluebird模塊,將node_redispromises化:
varredis=require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
它將在所有node_redis函數后添加一個Async (例如 return client.getAsync().then())
//Weexpectavalue'foo':'bar'tobepresent
//Soinsteadofwritingclient.get('foo',cb);youhavetowrite:
returnclient.getAsync('foo').then(function(res){
console.log(res);//=>'bar'
});
//Usingmultiwithpromiseslookslike:
returnclient.multi().get('foo').execAsync().then(function(res){
console.log(res);//=>'bar'
});
--------------------------------------------------
譯者注:
bluebird裝飾后可以結合ES6的await/async使用
varredis=require("redis"),
bluebird=require("bluebird");
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
letclient=redis.createClient();
(asyncfunction(){
awaitclient.setAsync("ip",1,"ex",10);
letip=awaitclient.getAsync("ip");
awaitclient.setAsync("ip",++ip,"ex",10);
ip=awaitclient.getAsync("ip");
console.log(ip)
})();
--------------------------------------------------
Sending Commands
發送命令
每個Redis命令都作為client對象上的一個函數暴露出來。所有函數都采用一個args數組加上可選的callback函數,或者一個可變數量的的單獨參數跟隨一個可選的回調。例如:
client.hmset(["key","testkeys1","testval1","testkeys2","testval2"],function(err,res){});
//Worksthesameas
client.hmset("key",["testkeys1","testval1","testkeys2","testval2"],function(err,res){});
//Or
client.hmset("key","testkeys1","testval1","testkeys2","testval2",function(err,res){});
Care should be taken with user input if arrays are possible (via body-parser, query string or other method), as single arguments could be unintentionally interpreted as multiple args.
(TODO)
注意,無論哪種形式,回調都是可選的:
client.set("somekey","someval");client.set(["someotherkey","someval"]);
如果key不存在,將返回null。只有當Redis Command Reference特別聲明,它才不會為空。
client.get("missingkey",function(err,reply){//replyisnullwhenthekeyismissing
console.log(reply);
});
Redis命令列表,請參見Redis Command Reference
在返回結果中進行了最低限度的解析。命令中,integer 返回Javascript的Numbers,arrays 返回JavaScript Array.HGETALL返回hash keys作為key的Object .所有strings 將返回 string ,亦或者你特別設置返回類型為buffer類型 。請注意:null, undefined 和Boolean 在返回中將強制轉換為字符串。
--------------------------------------------------
譯者注:
關于Boolean 在返回中將強制轉換為字符串。我做了如下demo
varredis=require("redis"),
client=redis.createClient();
client.set("stringkey",true);
client.get("stringkey",(err,key)=>{
console.log(typeofkey);
});
返回
string
--------------------------------------------------
Redis Commands
Redis命令
這個庫跟Redis命令一一映射。請參照Redis命令頁獲取完整的使用細節。
例如使用SET command設置key值得自動失效時間
//thiskeywillexpireafter10seconds
client.set('key','value!','EX',10);
API
Connection and other Events
客戶端將會發送一些關于連接到Redis服務器的狀態的事件。
"ready"
client當連接建立后,將觸發一次ready事件. 在ready事件之前發出的命令將被排隊,ready事件觸發后,隊列中的命令依次執行。
"connect"
一旦stream連接到服務器,client立即觸發connect事件。
--------------------------------------------------
譯者注:
關于“ready“,”connect”執行先后問題,設計了如下demo
varredis=require("redis"),
client=redis.createClient();
client.on("ready",()=>{
console.log("ready");
});
client.on("connect",()=>{
console.log("connect");
});
結果
connect ready
--------------------------------------------------
"reconnecting"
在失去連接后,當嘗試重新連接到Redis服務器,client將觸發reconnecting事件。監聽器將被傳遞一個包含delay(in ms) 和attempt(the attempt #) 屬性的對象。
"error"
當遇到連接到Redis服務器錯誤,或在node_redis中出現的任何其他錯誤時,client將觸發error事件。如果你使用一個沒有回調的命令,或者遇到返回異常時,錯誤監聽器將被觸發。
因此,請將錯誤偵聽器附加到node_redis上。
"end"
當已和Redis服務器建立的連接被關閉時,client將觸發end事件。
"drain" (deprecated棄用)
當TCP連接到Redis server曾經被緩存,但現在是可寫的(譯者注:緩存池排干時)。這個事件將被用于流命令進入Redis,并適應背壓。
當流被緩存client.should_buffer被設置為 true. 否則變量始終被設置為false。這樣你能夠決定何時降低發送速率,當觸發drain事件時再恢復傳輸。
您也可以檢查每個命令的返回值,因為它也將返回背壓指示器(不建議使用)。如果返回false,則流必須緩沖。
--------------------------------------------------
譯者注:
關于drain原理,可以參閱http://taobaofed.org/blog/2015/12/31/nodejs-drain/
我寫了一個drain測試demo
'usestrict';
varredis=require('redis');
varclient=redis.createClient({
return_buffers:true
});
client.auth("g7845120");
varfs=require('fs');
varfilename='Funny-Cat-GIFs.jpg';
fs.readFile(filename,function(err,data){
if(err)throwerr;
console.log('Read'+data.length+'bytesfromfilesystem.');
client.set(filename,data,function(){
console.log("setend")
});//setentirefile
if(client.should_buffer){
client.stream.pause();
}
client.stream.on("drain",function(){
console.log("drain");
client.stream.resume();
});
});
--------------------------------------------------
"warning"
當設置密碼時,但不需要,并且使用了一個不贊成的選項/功能/類似。client將觸發warning事件。
"idle" (deprecated棄用)
在沒有正在等待響應的未完成命令時發出時,client將觸發idle事件
redis.createClient()
如果你的node服務器和redis服務器運行在同一臺機器上,那么默認設置的port和host或許是可用的,并且你不需要提供其他參數。createClient()返回一個RedisClient對象。否則,createClient()需要接受這些參數:
redis.createClient([options])
redis.createClient(unix_socket[, options])
redis.createClient(redis_url[, options])
redis.createClient(port[, host][, options])
提示:如果Redis服務器與客戶端在同一臺計算機上運行,請盡可能使用unix套接字來增加吞吐量。
optionsobject properties
| Property | Default | Description |
|---|---|---|
| host | 127.0.0.1 |
IP address of the Redis server |
| port | 6379 | Port of the Redis server |
| path | null | The UNIX socket string of the Redis server |
| url | null | The URL of the Redis server. Format:[redis:]//[[user][:password@]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]](More info avaliable atIANA). |
| parser | javascript | DeprecatedUse either the built-in JS parserjavascriptor the nativehiredisparser.Notenode_redis< 2.6 uses hiredis as default if installed. This changed in v.2.6.0. |
| string_numbers | null |
設置為true,node_redis將返回String類型Redis的number值,以替代javascript的Nembers類型。當你需要處理一個大數字時有用(超過Number.MAX_SAFE_INTEGER === 2^53)。Hiredis無能為力,因此設置此選項 |
| return_buffers | false |
如果設置為true,那么所有的返回值將以Buffers的形式替代Strings發送到回調函數. |
| detect_buffers | false |
如果設置為 |
| socket_keepalive | true |
如果設置為 |
| no_ready_check | false | When a connection is established to the Redis server, the server might still be loading the database from disk. While loading, the server will not respond to any commands. To work around this,node_redishas a "ready check" which sends theINFOcommand to the server. The response from theINFOcommand indicates whether the server is ready for more commands. When ready,node_redisemits areadyevent. Settingno_ready_checktotruewill inhibit this check. |
| enable_offline_queue | true | By default, if there is no active connection to the Redis server, commands are added to a queue and are executed once the connection has been established. Settingenable_offline_queuetofalsewill disable this feature and the callback will be executed immediately with an error, or an error will be emitted if no callback is specified. |
| retry_max_delay | null | DeprecatedPlease useretry_strategyinstead.By default, every time the client tries to connect and fails, the reconnection delay almost doubles. This delay normally grows infinitely, but settingretry_max_delaylimits it to the maximum value provided in milliseconds. |
| connect_timeout | 3600000 | DeprecatedPlease useretry_strategyinstead.Settingconnect_timeoutlimits the total time for the client to connect and reconnect. The value is provided in milliseconds and is counted from the moment a new client is created or from the time the connection is lost. The last retry is going to happen exactly at the timeout time. Default is to try connecting until the default system socket timeout has been exceeded and to try reconnecting until 1h has elapsed. |
| max_attempts | 0 | DeprecatedPlease useretry_strategyinstead.By default, a client will try reconnecting until connected. Settingmax_attemptslimits total amount of connection attempts. Setting this to 1 will prevent any reconnect attempt. |
| retry_unfulfilled_commands | false | If set totrue, all commands that were unfulfilled while the connection is lost will be retried after the connection has been reestablished. Use this with caution if you use state altering commands (e.g.incr). This is especially useful if you use blocking commands. |
| password | null | If set, client will run Redis auth command on connect. Aliasauth_passNotenode_redis< 2.5 must useauth_pass |
| db | null | If set, client will run Redisselectcommand on connect. |
| family | IPv4 | You can force using IPv6 if you set the family to 'IPv6'. See Node.jsnetordnsmodules on how to use the family type. |
| disable_resubscribing | false | If set totrue, a client won't resubscribe after disconnecting. |
| rename_commands | null | Passing an object with renamed commands to use instead of the original functions. For example, if you renamed the command KEYS to "DO-NOT-USE" then the rename_commands object would be:{ KEYS : "DO-NOT-USE" }. See theRedis security topicsfor more info. |
| tls | null | An object containing options to pass totls.connectto set up a TLS connection to Redis (if, for example, it is set up to be accessible via a tunnel). |
| prefix | null | A string used to prefix all used keys (e.g.namespace:test). Please be aware that thekeyscommand will not be prefixed. Thekeyscommand has a "pattern" as argument and no key and it would be impossible to determine the existing keys in Redis if this would be prefixed. |
| retry_strategy | function | 這是一個函數,接受一個option對象作為參數,其參數包含重試attempt,指示距離最后一次連接的時間total_retry_time,為什么連接失敗的error和總共重連次數的times_connected。如果在這個函數中你返回一個數字,那么將在這個數字的毫秒數的時間后嘗試重連。如果你返回一個非數字,則不會再發生重連,并且所有脫機命令將會刷新并顯示錯誤。返回一個錯誤,將特定錯誤返回給所有脫機命令。下面的例子。 |
varredis=require("redis");
varclient=redis.createClient({detect_buffers:true});
client.set("foo_rand000000000000","OK");
//ThiswillreturnaJavaScriptString
client.get("foo_rand000000000000",function(err,reply){
console.log(reply.toString());//Willprint`OK`
});
//ThiswillreturnaBuffersinceoriginalkeyisspecifiedasaBuffer
client.get(newBuffer("foo_rand000000000000"),function(err,reply){
console.log(reply);//Willprint`<Buffer4f4b>`
//譯者注:官網的代碼是console.log(reply.toString());這會輸出ok而不是`<Buffer4f4b>`
});
client.quit();
retry_strategy example
varclient=redis.createClient({
retry_strategy:function(options){
if(options.error&&options.error.code==='ECONNREFUSED'){
//Endreconnectingonaspecificerrorandflushallcommandswith
//aindividualerror
returnnewError('Theserverrefusedtheconnection');
}
if(options.total_retry_time>1000*60*60){
//Endreconnectingafteraspecifictimeoutandflushallcommands
//withaindividualerror
returnnewError('Retrytimeexhausted');
}
if(options.attempt>10){
//Endreconnectingwithbuiltinerror
returnundefined;
}
//reconnectafter
returnMath.min(options.attempt*100,3000);
}
});
client.auth(password[, callback])
當連接的Redis服務器需要安全認證,AUTH命令必須在連接后作為第一條命令被發送。這可能需要與重新連接、就緒的檢查等進行協調。為了更方便,client.auth()儲存password ,并在以后的每個連接,包括重連時發送它。回調只在對第一個AUTH命令發出的響應之后才調用一次。注意:你調用client.auth() 不應該在ready事件的處理函數中。如果你執行了這個錯誤,client將觸發類似這樣的錯誤:Ready check failed: ERR operation not permitted.
--------------------------------------------------
譯者注:
varredis=require("redis")
letclient=redis.createClient();
client.on("ready",()=>{
console.log("ready")
client.auth("g7845120");
});
返回
ReplyError:Readycheckfailed:NOAUTHAuthenticationrequired.
--------------------------------------------------
backpressure
stream
client 在client.stream中暴露使用的stream并且在client.should_buffer中暴露流或者客戶端是否不得不被緩存。結合這些,你可以通過在發送一個命令前檢查buffer狀態并且監聽stream的drain事件實現背壓。
client.quit()
這會將退出命令發送到redis服務器,并在正確處理所有運行的命令之后以干凈的方式結束。如果這是在重新連接時調用的(因此不存在與redis服務器的連接),它將立即終止連接,而不是產生進一步的重新連接!在這種情況下,所有的離線命令都將被一個錯誤所刷新。
client.end(flush)
強行關閉與Redis服務器的連接。注意,這不會等到所有的回復都被解析后才會出現。如果您想要干凈地退出,請調用上述client.quit()。
如果您不完全確定您不關心其他命令,那么您應該將flush設置為true。如果您將flush設置為false,所有仍然運行的命令將會無聲地失敗。
這個例子在讀取回復之前關閉了與Redis服務器的連接。你可能不想這樣做:
varredis=require("redis"),
client=redis.createClient();
client.set("foo_rand000000000000","somefantasticvalue",function(err,reply){
//Thiswilleitherresultinanerror(flushparameterissettotrue)
//orwillsilentlyfailandthiscallbackwillnotbecalledatall(flushsettofalse)
console.log(err);
});
client.end(true);//Nofurthercommandswillbeprocessed
client.get("foo_rand000000000000",function(err,reply){
console.log(err);//=>'Theconnectionhasalreadybeenclosed.'
});
client.end()如果不將flush參數設置為true,就不應該在生產中使用!
Error handling (>= v.2.6)
當前存在以下錯誤子類:
RedisError:客戶端返回的所有錯誤
ReplyErrorRedisError的子類: All errors returned byRedisitself
AbortErrorRedisError的子類: 由于某種原因所有的命令無法完成而中斷
ParserErrorRedisError的子類:返回解析錯誤時返回(這不應該發生)
AggregateErrorRedisError的子類:如果沒有回調的多個未解決的命令被釋放,在調試模式中會被rejected,而不是大量的AbortErrors。
所有的錯誤類都是由模塊導出的。
Example:
varredis=require('./');
varassert=require('assert');
varclient=redis.createClient();
client.on('error',function(err){
assert(errinstanceofError);
assert(errinstanceofredis.AbortError);
assert(errinstanceofredis.AggregateError);
//Thesetandgetgetaggregatedinhere
assert.strictEqual(err.errors.length,2);
assert.strictEqual(err.code,'NR_CLOSED');
});
client.set('foo',123,'bar',function(err,res){//Toomanyarguments
assert(errinstanceofredis.ReplyError);//=>true
assert.strictEqual(err.command,'SET');
assert.deepStrictEqual(err.args,['foo',123,'bar']);
redis.debug_mode=true;
client.set('foo','bar');
client.get('foo');
process.nextTick(function(){
//Forceclosingtheconnectionwhilethecommanddidnotyetreturn
client.end(true);
redis.debug_mode=false;
});
});
每個ReplyError都包含有全大寫的command名和參數(args)。
--------------------------------------------------
譯者注:
varredis=require('redis');
varassert=require('assert');
varclient=redis.createClient();
client.set('foo',123,'bar',function(err,res){//Toomanyarguments
assert(errinstanceofredis.ReplyError);//=>true
console.log(err)
console.log("command:"+err.command);
console.log("args:",err.args);
console.log("code:"+err.code);
});
返回
{ReplyError:ERRsyntaxerror
atparseError(F: estedis-test
ode_modulesedis-parserlibparser.js:193:12)
atparseType(F: estedis-test
ode_modulesedis-parserlibparser.js:303:14)command:'SET',args:['foo',123,'bar'],code:'ERR'}
command:SET
args:['foo',123,'bar']
code:ERR
--------------------------------------------------
如果node_redis由于其他錯誤而發出庫錯誤,則將觸發錯誤添加到返回的錯誤中,作為origin屬性。
Error codes
如果客戶端連接失敗,noderedis返回一個NR_CLOSED的錯誤代碼。如果一個命令未解決的命令被拒絕,則返回一個UNCERTAIN_STATE的代碼。如果節點redis放棄了重新連接,則使用一個CONNECTION_BROKEN的錯誤代碼。
--------------------------------------------------
譯者注:
varredis=require('redis');
varassert=require('assert');
varclient=redis.createClient();
client.on('error',function(err){
console.log(err.code)
});
redis.debug_mode=true;
client.set('foo','bar');
process.nextTick(function(){
//Forceclosingtheconnectionwhilethecommanddidnotyetreturn
client.end(true);
redis.debug_mode=false;
});
返回
NR_CLOSED
--------------------------------------------------
client.unref()
在與Redis服務器的底層套接字連接上調用unref(),允許程序在不需要更多命令的情況下退出。
這是一個實驗性的特性,并且只支持Redis協議的一個子集。任何在Redis服務器上保存客戶端狀態的命令,例如訂閱或阻塞的BL命令都不能與.unref()一起工作。
varredis=require("redis")
varclient=redis.createClient()
/*
Callingunref()willallowthisprogramtoexitimmediatelyaftertheget
commandfinishes.Otherwisetheclientwouldhangaslongasthe
client-serverconnectionisalive.
調用unref()將允許該程序在get命令完成之后立即退出
。否則客戶端和服務器連接將一直保持。
*/
client.unref()
client.get("foo",function(err,value){
if(err)throw(err)
console.log(value)
})
Friendlier hash commands
友好的hash命令
大多數Redis命令都使用單個字符串或字符串數組作為參數,并且返回響應單個字符串或字符串數組。在處理hash值時,有幾個有用的例外。
client.hgetall(hash, callback)
HGETALL命令的響應將會被node_redis轉換為JavaScript對象。這樣,你就能夠用JavaScript語法與響應進行交互了。
Example:
client.hmset("hosts","mjr","1","another","23","home","1234");
client.hgetall("hosts",function(err,obj){
console.dir(obj);
});
Output:
{mjr:'1',another:'23',home:'1234'}
client.hmset(hash, obj[, callback])
Multiple values in a hash can be set by supplying an object:
client.HMSET(key2,{
"0123456789":"abcdefghij",//NOTE:keyandvaluewillbecoercedtostrings
"somemannerofkey":"atypeofvalue"
});
The properties and values of this Object will be set as keys and values in the Redis hash.
client.hmset(hash, key1, val1, ... keyn, valn, [callback])
Multiple values may also be set by supplying a list:
client.HMSET(key1,"0123456789","abcdefghij","somemannerofkey","atypeofvalue");
Publish / Subscribe
發布/訂閱API的例子。該程序打開兩個客戶端連接,訂閱其中一個通道,并在另一個通道上發布該通道:
varredis=require("redis");
varsub=redis.createClient(),pub=redis.createClient();
varmsg_count=0;
sub.on("subscribe",function(channel,count){
pub.publish("anicechannel","Iamsendingamessage.");
pub.publish("anicechannel","Iamsendingasecondmessage.");
pub.publish("anicechannel","Iamsendingmylastmessage.");
});
sub.on("message",function(channel,message){
console.log("subchannel"+channel+":"+message);
msg_count+=1;
if(msg_count===3){
sub.unsubscribe();
sub.quit();
pub.quit();
}
});
sub.subscribe("anicechannel");
--------------------------------------------------
譯者注:
varredis=require("redis");
varsub=redis.createClient(),pub=redis.createClient();
varmsg_count=0;
sub.on("subscribe",function(channel,count){
pub.publish("anicechannel","Iamsendingamessage.");
pub.publish("anicechannel","Iamsendingasecondmessage.");
pub.publish("anicechannel","Iamsendingmylastmessage.");
pub.publish("anicechannel","Iamsendingmylastmessage.");//仍會接收
setTimeout(()=>{
pub.publish("anicechannel","Iamsendingmylastmessage.");//將會遺棄
},1000)
});
sub.on("message",function(channel,message){
console.log("subchannel"+channel+":"+message);
msg_count+=1;
if(msg_count===3){
sub.unsubscribe();
sub.quit();
}
});
sub.subscribe("anicechannel");
--------------------------------------------------
當客戶機發出訂閱或訂閱時,該連接將被放入“訂閱者”模式。在這一點上,只有修改訂閱集的命令是有效的(TODO)。當訂閱集為空時,連接將被放回常規模式。
如果您需要在訂閱模式下向Redis發送常規命令,只需打開另一個與新客戶機的連接(提示:使用client.duplicate())。
Subscriber Events
如果客戶端有訂閱活動,它可能會發出這些事件:
"message" (channel, message)
客戶端將為收到的每一條與活動的訂閱相匹配的消息發出message 事件。偵聽器參數以channel作為頻道名稱,并以message作為消息。
"pmessage" (pattern, channel, message)
客戶端將為收到的每一條與活動訂閱模式相匹配的消息發出pmessage事件。偵聽器參數以PSUBSCRIBE作為原始的正則匹配模式 、以channel作為頻道名稱,并以message作為消息。
--------------------------------------------------
譯者注:
源碼中查找demo如下
'usestrict';
varredis=require('redis');
varclient1=redis.createClient();
varclient2=redis.createClient();
varclient3=redis.createClient();
varclient4=redis.createClient();
varmsg_count=0;
client1.on('psubscribe',function(pattern,count){
console.log('client1psubscribedto'+pattern+','+count+'totalsubscriptions');
client2.publish('channeltwo','Me!');
client3.publish('channelthree','Metoo!');
client4.publish('channelfour','Andmetoo!');
});
client1.on('punsubscribe',function(pattern,count){
console.log('client1punsubscribedfrom'+pattern+','+count+'totalsubscriptions');
client4.end();
client3.end();
client2.end();
client1.end();
});
client1.on('pmessage',function(pattern,channel,message){
console.log('('+pattern+')client1receivedmessageon'+channel+':'+message);
msg_count+=1;
if(msg_count===3){
client1.punsubscribe();
}
});
client1.psubscribe('channel*');
由于channel*正則匹配了channeltwo、channelthree、channelfour。client1就能接收到這三個頻道的消息。
--------------------------------------------------
"message_buffer" (channel, message)
This is the same as themessageevent with the exception, that it is always going to emit a buffer. If you listen to themessageevent at the same time as themessage_buffer, it is always going to emit a string.
(TODO)
"pmessage_buffer" (pattern, channel, message)
This is the same as thepmessageevent with the exception, that it is always going to emit a buffer. If you listen to thepmessageevent at the same time as thepmessage_buffer, it is always going to emit a string.
(TODO)
"subscribe" (channel, count)
客戶端根據SUBSCRIBE命令觸發subscribe事件。偵聽器參數以channel作為頻道名稱,并以count作為新訂閱者數量。
"psubscribe" (pattern, count)
客戶端根據PSUBSCRIBE命令觸發psubscribe事件。偵聽器參數以pattern作為原始的正則匹配模式,并以count作為新訂閱者數量。
"unsubscribe" (channel, count)
客戶端根據UNSUBSCRIBE命令觸發unsubscribe事件。偵聽器參數以channel作為頻道名稱,并以count作為新訂閱者數量。當count為0時,客戶端將退出訂閱者模式,并且不再有訂閱者事件觸發。
"punsubscribe" (pattern, count)
客戶端根據PUNSUBSCRIBE命令觸發punsubscribe事件。偵聽器參數以pattern作為原始的正則匹配模式,并以count作為新訂閱者數量。當count為0時,客戶端將退出訂閱者模式,并且不再有訂閱者事件觸發。
client.multi([commands])
MULTI命令排隊直到一個EXEC 命令被執行,然后所有的命令都由Redis原子運行。node_redis的接口是通過調用client.multi()返回一個單獨的Multi對象。如果隊列中任何命令執行失敗,那么所有命令都會被回滾,并且不會執行任何操作(更多信息查看transactions)。
varredis=require("./index"),
client=redis.createClient(),set_size=20;
client.sadd("bigset","amember");
client.sadd("bigset","anothermember");
while(set_size>0){
client.sadd("bigset","member"+set_size);
set_size-=1;
}
//multichainwithanindividualcallback
client.multi()
.scard("bigset")
.smembers("bigset")
.keys("*",function(err,replies){
//NOTE:codeinthiscallbackisNOTatomic
//thisonlyhappensafterthethe.execcallfinishes.
client.mget(replies,redis.print);
})
.dbsize()
.exec(function(err,replies){
console.log("MULTIgot"+replies.length+"replies");
replies.forEach(function(reply,index){
console.log("Reply"+index+":"+reply.toString());
});
});
Multi.exec([callback])
client.multi()是一個返回Multi對象的構造函數。Multi對象與client對象共享所有相同的命令方法。在multi對象中,直到multi.exec()被調用,命令才被調用。
如果您的代碼包含一個語法錯誤,那么將會拋出一個EXECABORT 錯誤,所有的命令都將被中止。那個錯誤包含一個.errors屬性以描述具體的錯誤。如果所有命令都成功地排隊,并且并且一個錯誤在redis執行命令的過程中被拋出,那么錯誤將在結果數組中被返回!除了onces失敗之外,其他命令不會被中止。
您可以像上面的示例中將多個命令鏈接,或者您仍然可以如以下例子那樣,排列并發送單條普通命令,
varredis=require("redis"),
client=redis.createClient(),multi;
//startaseparatemulticommandqueue
multi=client.multi();
multi.incr("incrthing",redis.print);
multi.incr("incrotherthing",redis.print);
//runsimmediately
client.mset("incrthing",100,"incrotherthing",1,redis.print);
//drainsmultiqueueandrunsatomically
multi.exec(function(err,replies){
console.log(replies);//101,2
});
除了向多隊列添加命令之外,還可以向構造函數傳遞一個命令和參數數組:
varredis=require("redis"),
client=redis.createClient();
client.multi([
["mget","multifoo","multibar",redis.print],
["incr","multifoo"],
["incr","multibar"]
]).exec(function(err,replies){
console.log(replies);
});
Multi.exec_atomic([callback])
與Multi.exec類似,但是區別是執行單個命令時不會使用事務。
client.batch([commands])
與 .multi 相同但沒有事務。如果您希望同時執行多個命令,但不需要依賴事務,那么建議您這樣做。
BATCH批處理命令在隊列中排隊等待執行,然后所有的命令都由Redis原子運行。node_redis中的接口是通過調用client.Batch()來返回一個單獨的Batch處理對象。.batch和.multi的唯一區別是.batch沒有事務。注意,錯誤-就像在multi語句中一樣-返回在結果中。否則,錯誤和結果都可以同時返回。
如果您同時觸發多個命令,那么這與一個循環中執行相同的命令相比將大大提高執行速度,而不需要等待結果!查看benchmarks 獲取更多比較信息。請記住,所有的命令都保存在內存中,直到它們被觸發。
Monitor mode
Redis支持MONITOR命令,它讓您可以看到所有客戶端連接的所有命令,包括來自其他客戶端庫和其他計算機。
對于連接到服務器的任何客戶端發出的每個命令,都會發出一個monitor事件,包括monitoring客戶端本身。monitor事件的回調從Redis服務器獲取時間戳,一個命令參數數組和原始監控字符串。
Example:
varclient=require("redis").createClient();
client.monitor(function(err,res){
console.log("Enteringmonitoringmode.");
});
client.set('foo','bar');
client.on("monitor",function(time,args,raw_reply){
console.log(time+":"+args);//1458910076.446514:['set','foo','bar']
});
Extras
還有一些你可能想知道的事情。
client.server_info
在就緒的探測完成之后,INFO命令的結果將保存在client.server_info對象中。
versions鍵包含以版本字符串的字符組成的數組中,以便進行比較。
>client.server_info.redis_version '2.3.0' >client.server_info.versions [2,3,0]
redis.print()
一個方便的回調函數,用于在測試時顯示返回值。例子:
varredis=require("redis"),
client=redis.createClient();
client.on("connect",function(){
client.set("foo_rand000000000000","somefantasticvalue",redis.print);
client.get("foo_rand000000000000",redis.print);
});
This will print:
Reply:OK Reply:somefantasticvalue
注意,這個程序不會干凈地退出,因為客戶端仍然是連接的。
Multi-word commands
執行redis的multi-word命令,如SCRIPT LOAD或CLIENT LIST,將第二個單詞作為第一個參數傳遞:
client.script('load','return1');
client.multi().script('load','return1').exec(...);
client.multi([['script','load','return1']]).exec(...);
client.duplicate([options][, callback])
復制所有當前選項并返回一個新的redisClient實例。傳遞給duplicate函數的所有選項都將替換原來的選項。如果您傳遞一個回調,duplicate將等待客戶端準備好并在回調中返回它。如果與此同時發生錯誤,則會返回一個錯誤,而不是在回調中。
使用duplicate()的一個例子包含如下連接——阻塞的redis命令BRPOP、BLPOP和BRPOPLPUSH。如果這些命令在與非阻塞命令相同的redisClient實例上使用,則非阻塞的命令可能會排隊直到阻塞的命令結束。
varRedis=require('redis');
varclient=Redis.createClient();
varclientBlocking=client.duplicate();
varget=function(){
console.log("getcalled");
client.get("any_key",function(){console.log("getreturned");});
setTimeout(get,1000);
};
varbrpop=function(){
console.log("brpopcalled");
clientBlocking.brpop("nonexistent",5,function(){
console.log("brpopreturn");
setTimeout(brpop,1000);
});
};
get();
brpop();
使用duplicate()的另一個原因是,通過redis SELECT命令訪問同一個服務器上的多個DBs。每個DB都可以使用它自己的連接。
client.send_command(command_name[, [args][, callback]])
所有的Redis命令都被添加到客戶端對象中。但是,如果在這個庫更新之前引入了新的命令,或者如果您想要添加單獨的命令,那么可以使用sendcommand()向Redis發送任意命令。
所有命令都是作為多批量命令發送的。args可以是一組參數,也可以是未定義的參數。
client.add_command(command_name)
調用add_command將向原型添加一個新的命令。在使用這個新命令調用時,將使用精確的命令名。使用任意參數與任何其他命令一樣是可能的。
client.connected
跟蹤連接到Redis服務器的連接狀態的布爾值。
client.command_queue_length
The number of commands that have been sent to the Redis server but not yet replied to. You can use this to enforce some kind of maximum queue depth for commands while connected.
client.offline_queue_length
已經發送到Redis服務器但還沒有回復的命令數量。你可以使用這條命令為pre-connection命令去執行一些類別的最大隊列深度。
Commands with Optional and Keyword arguments
這適用于任何使用一個可選的在redis.io/commands文檔中的[WITHSCORES]或[LIMIT offset count]。
Example:
varargs=['myzset',1,'one',2,'two',3,'three',99,'ninety-nine'];
client.zadd(args,function(err,response){
if(err)throwerr;
console.log('added'+response+'items.');
//-Infinityand+Infinityalsowork
varargs1=['myzset','+inf','-inf'];
client.zrevrangebyscore(args1,function(err,response){
if(err)throwerr;
console.log('example1',response);
//writeyourcodehere
});
varmax=3,min=1,offset=1,count=2;
varargs2=['myzset',max,min,'WITHSCORES','LIMIT',offset,count];
client.zrevrangebyscore(args2,function(err,response){
if(err)throwerr;
console.log('example2',response);
//writeyourcodehere
});
});
Performance
為了使node_redis盡可能快地進行普通操作,花費了大量的精力。
LenovoT450s,i7-5600Uand12gbmemory clients:1,NodeJS:6.2.0,Redis:3.2.0,parser:javascript,connectedby:tcp PING,1/1avg/max:0.02/5.262501mstotal,46916ops/sec PING,batch50/1avg/max:0.06/4.352501mstotal,755178ops/sec SET4Bstr,1/1avg/max:0.02/4.752501mstotal,40856ops/sec SET4Bstr,batch50/1avg/max:0.11/1.512501mstotal,432727ops/sec SET4Bbuf,1/1avg/max:0.05/2.762501mstotal,20659ops/sec SET4Bbuf,batch50/1avg/max:0.25/1.762501mstotal,194962ops/sec GET4Bstr,1/1avg/max:0.02/1.552501mstotal,45156ops/sec GET4Bstr,batch50/1avg/max:0.09/3.152501mstotal,524110ops/sec GET4Bbuf,1/1avg/max:0.02/3.072501mstotal,44563ops/sec GET4Bbuf,batch50/1avg/max:0.10/3.182501mstotal,473171ops/sec SET4KiBstr,1/1avg/max:0.03/1.542501mstotal,32627ops/sec SET4KiBstr,batch50/1avg/max:0.34/1.892501mstotal,146861ops/sec SET4KiBbuf,1/1avg/max:0.05/2.852501mstotal,20688ops/sec SET4KiBbuf,batch50/1avg/max:0.36/1.832501mstotal,138165ops/sec GET4KiBstr,1/1avg/max:0.02/1.372501mstotal,39389ops/sec GET4KiBstr,batch50/1avg/max:0.24/1.812501mstotal,208157ops/sec GET4KiBbuf,1/1avg/max:0.02/2.632501mstotal,39918ops/sec GET4KiBbuf,batch50/1avg/max:0.31/8.562501mstotal,161575ops/sec INCR,1/1avg/max:0.02/4.692501mstotal,45685ops/sec INCR,batch50/1avg/max:0.09/3.062501mstotal,539964ops/sec LPUSH,1/1avg/max:0.02/3.042501mstotal,41253ops/sec LPUSH,batch50/1avg/max:0.12/1.942501mstotal,425090ops/sec LRANGE10,1/1avg/max:0.02/2.282501mstotal,39850ops/sec LRANGE10,batch50/1avg/max:0.25/1.852501mstotal,194302ops/sec LRANGE100,1/1avg/max:0.05/2.932501mstotal,21026ops/sec LRANGE100,batch50/1avg/max:1.52/2.892501mstotal,32767ops/sec SET4MiBstr,1/1avg/max:5.16/15.552502mstotal,193ops/sec SET4MiBstr,batch20/1avg/max:89.73/99.962513mstotal,223ops/sec SET4MiBbuf,1/1avg/max:2.23/8.352501mstotal,446ops/sec SET4MiBbuf,batch20/1avg/max:41.47/50.912530mstotal,482ops/sec GET4MiBstr,1/1avg/max:2.79/10.912502mstotal,358ops/sec GET4MiBstr,batch20/1avg/max:101.61/118.112541mstotal,197ops/sec GET4MiBbuf,1/1avg/max:2.32/14.932502mstotal,430ops/sec GET4MiBbuf,batch20/1avg/max:65.01/84.722536mstotal,308ops/sec
Debugging
為了獲得調試輸出,您可以在node_redis應用程序中使用NODE_DEBUG=redis。
這也會導致好的堆棧跟蹤,而不是無用的堆棧跟蹤,否則對于任何異步操作都是如此。如果您只想擁有好的堆棧跟蹤,而不是調試輸出,請在開發模式中運行您的應用程序(NODE_ENV=development)。
好的堆棧跟蹤只在開發和調試模式中被激活,因為這將導致嚴重的性能損失。
Comparison: Useless stack trace:
ReplyError:ERRwrongnumberofargumentsfor'set'command atparseError(/home/ruben/repos/redis/node_modules/redis-parser/lib/parser.js:158:12) atparseType(/home/ruben/repos/redis/node_modules/redis-parser/lib/parser.js:219:14)
Good stack trace:
ReplyError:ERRwrongnumberofargumentsfor'set'command atnewCommand(/home/ruben/repos/redis/lib/command.js:9:902) atRedisClient.set(/home/ruben/repos/redis/lib/commands.js:9:3238) atContext.<anonymous>(/home/ruben/repos/redis/test/good_stacks.spec.js:20:20) atcallFnAsync(/home/ruben/repos/redis/node_modules/mocha/lib/runnable.js:349:8) atTest.Runnable.run(/home/ruben/repos/redis/node_modules/mocha/lib/runnable.js:301:7) atRunner.runTest(/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:422:10) at/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:528:12 atnext(/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:342:14) at/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:352:7 atnext(/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:284:14) atImmediate._onImmediate(/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:320:5) atprocessImmediate[as_immediateCallback](timers.js:383:17)
How to Contribute
Open a pull request or an issue about what you want to implement / change. We're glad for any help!
Please be aware that we'll only accept fully tested code.
Contributors
The original author of node_redis isMatthew Ranney
The current lead maintainer isRuben Bridgewater
Manyotherscontributed tonode_redistoo. Thanks to all of them!
License
MIT
Consolidation: It's time for celebration
Right now there are two great redis clients around and both have some advantages above each other. We speak about ioredis and node_redis. So after talking to each other about how we could improve in working together we (that is @luin and @BridgeAR) decided to work towards a single library on the long run. But step by step.
First of all, we want to split small parts of our libraries into others so that we're both able to use the same code. Those libraries are going to be maintained under the NodeRedis organization. This is going to reduce the maintenance overhead, allows others to use the very same code, if they need it and it's way easyer for others to contribute to both libraries.
We're very happy about this step towards working together as we both want to give you the best redis experience possible.
If you want to join our cause by help maintaining something, please don't hesitate to contact either one of us.
總結
以上是生活随笔為你收集整理的node_redis 中文文档及node_redis 注释笔记(中文版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Chrome开发者工具Element s
- 下一篇: rxjs of操作符传入数组的单步执行