About generic-pool
github地址:https://github.com/coopernurse/node-pool
description:
Generic resource pool. Can be used to reuse or throttle expensive resources such as database connections.
由此可以看出,该模块是一般的资源池,用来重复使用昂贵的资源,比如数据库连接等。
使用这个模块
Step 1:创建资源池
<code class="hljs sql has-numbering">//Step 1 - <span class="hljs-operator"><span class="hljs-keyword">Create</span> pool <span class="hljs-keyword">using</span> a factory object // <span class="hljs-keyword">Create</span> a MySQL <span class="hljs-keyword">connection</span> pool <span class="hljs-keyword">with</span>,创建Mysql连接 // a <span class="hljs-aggregate">max</span> <span class="hljs-keyword">of</span> <span class="hljs-number">10</span> connections, a <span class="hljs-aggregate">min</span> <span class="hljs-keyword">of</span> <span class="hljs-number">2</span>, <span class="hljs-keyword">and</span> a <span class="hljs-number">30</span> <span class="hljs-keyword">second</span> <span class="hljs-aggregate">max</span> idle <span class="hljs-keyword">time</span> var Pool = require(<span class="hljs-string">'generic-pool'</span>).Pool;</span> var mysql = require('mysql'); // v2.10.x var pool = new Pool({ name : 'mysql', <span class="hljs-operator"><span class="hljs-keyword">create</span> : function(callback) { //创建连接 var c = mysql.createConnection({ <span class="hljs-keyword">user</span>: <span class="hljs-string">'scott'</span>, password: <span class="hljs-string">'tiger'</span>, <span class="hljs-keyword">database</span>:<span class="hljs-string">'mydb'</span> }) // parameter <span class="hljs-keyword">order</span>: err, resource callback(<span class="hljs-keyword">null</span>, c);</span> }, //销毁连接 destroy : function(client) { client.<span class="hljs-operator"><span class="hljs-keyword">end</span>();</span> }, //最大并发数 max : 10, // optional. if you <span class="hljs-operator"><span class="hljs-keyword">set</span> this, make sure <span class="hljs-keyword">to</span> drain() (see step <span class="hljs-number">3</span>),如果设置了并发数,记得在不使用时执行drain()方法,(英文意思为排干,流尽) //最小并发数 <span class="hljs-aggregate">min</span> : <span class="hljs-number">2</span>, // specifies how long a resource can stay idle <span class="hljs-keyword">in</span> pool <span class="hljs-keyword">before</span> being removed,idle:资源超时时间 idleTimeoutMillis : <span class="hljs-number">30000</span>, // <span class="hljs-keyword">if</span> <span class="hljs-keyword">true</span>, logs via console.log - can also be a function //是否打印日志,log可以为一个函数,执行函数log log : <span class="hljs-keyword">true</span> });</span> Step 3 - Drain pool during shutdown (optional) If you are shutting down a long-lived process, you may notice that node fails to exit for 30 seconds or so. This is a side effect of the idleTimeoutMillis behavior <span class="hljs-comment">-- the pool has a setTimeout() call registered that is in the event loop queue, so node won't terminate until all resources have timed out, and the pool stops trying to manage them.</span> This behavior will be more problematic when you <span class="hljs-operator"><span class="hljs-keyword">set</span> factory.<span class="hljs-aggregate">min</span> > <span class="hljs-number">0</span>, <span class="hljs-keyword">as</span> the pool will never become empty, <span class="hljs-keyword">and</span> the setTimeout calls will never <span class="hljs-keyword">end</span>. <span class="hljs-keyword">In</span> these cases, use the pool.drain() function. This sets the pool <span class="hljs-keyword">into</span> a <span class="hljs-string">"draining"</span> state which will gracefully wait until <span class="hljs-keyword">all</span> idle resources have timed out. <span class="hljs-keyword">For</span> example, you can <span class="hljs-keyword">call</span>: // <span class="hljs-keyword">Only</span> <span class="hljs-keyword">call</span> this once <span class="hljs-keyword">in</span> your application -- <span class="hljs-keyword">at</span> the point you want // <span class="hljs-keyword">to</span> shutdown <span class="hljs-keyword">and</span> stop <span class="hljs-keyword">using</span> this pool. pool.drain(function() { pool.destroyAllNow();</span> });</code>
Step 2:使用资源池(acquire,release)
<code class="hljs javascript has-numbering"><span class="hljs-comment">//Step 2 - Use pool in your code to acquire/release resources</span> <span class="hljs-comment">// acquire connection - callback function is called</span> <span class="hljs-comment">// once a resource becomes available</span> pool.acquire(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(err, client)</span> {</span> <span class="hljs-keyword">if</span> (err) { <span class="hljs-comment">// handle error - this is generally the err from your</span> <span class="hljs-comment">// factory.create function</span> } <span class="hljs-keyword">else</span> { client.query(<span class="hljs-string">"select * from foo"</span>, [], <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span> <span class="hljs-comment">// return object back to pool,将资源对象返回给资源池</span> pool.release(client); }); } });</code>
Step 3:把资源池的水排干,可选
在一个已经运行了很长的进程中,如果你想把资源池关闭了,你可能会发现,有节点会在30s后才执行关闭动作。这个是由设置的idleTimeoutMillis 引发的副作用:资源池存在一个setTimeout()调用,该调用被添加到事件循环队列中,所以该节点不能被关闭,直到所有的资源都超时,此时,资源池将不会对这些资源进行管理。
这样的行为,当设置最小并发数大于0的时候,这样如果关闭的话,将会导致该资源池永远都不能为空,而存在于事件循环队列的setTimeout()调用将永远得不到执行。
如上面的情况,应该使用pool.drain()函数,这个函数会将资源池里的所有资源都清除干净,在任何你想关闭或者停止使用资源池的地方调用它,并且这个函数只能被执行一次 如:
<code class="hljs javascript has-numbering">pool.drain(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span> pool.destroyAllNow(); });</code>
Pool
<code class="hljs php has-numbering">git <span class="hljs-keyword">clone</span> https:<span class="hljs-comment">//github.com/coopernurse/node-pool.git</span></code>
发现主要的代码就位于lib文件夹中的generic-pool.js,打开代码,发现只有580行,这更激起我阅读该模块的兴趣了。。
源码的第580行导出了Pool,故先看Pool类
<code class="hljs fix has-numbering"><span class="hljs-attribute">exports.Pool </span>=<span class="hljs-string"> Pool</span></code>
Pool构造函数
<code class="hljs coffeescript has-numbering">/** * Generate an Object pool <span class="hljs-reserved">with</span> a specified `<span class="javascript">factory</span>`. * * <span class="hljs-property">@class</span> * <span class="hljs-property">@param</span> {Object} factory * 用来生成和删除实例 * <span class="hljs-property">@param</span> {String} factory.name * 工厂的名字,主要用来写log用 * <span class="hljs-property">@param</span> {Function} factory.create * 生成实例所必须的方法,生成后执行回调,将以回调参数的形式返回给调用资源池者。 * <span class="hljs-property">@param</span> {Function} factory.destroy * 温柔滴关闭正在运行的资源。 * <span class="hljs-property">@param</span> {Function} factory.validate * 在acquire中返回前判断资源是否有效,默认为有效 * <span class="hljs-property">@param</span> {Function} factory.validateAsync * 同步调用 * <span class="hljs-property">@param</span> {Number} factory.max * 最大并发数,默认为<span class="hljs-number">1.</span> * <span class="hljs-property">@param</span> {Number} factory.min * 最小并发数,默认为<span class="hljs-number">0</span> * 一旦资源池被创建或者资源被回收的时候,需要检查资源池的资源是否小于并发数,以下,如果小于并发数以下,应该创建新的资源并将其加入到资源池中。 * <span class="hljs-property">@param</span> {Number} factory.idleTimeoutMillis * 超时时间,单位为毫秒,超时回收 * <span class="hljs-property">@param</span> {Number} factory.reapIntervalMillis * 检查空闲资源的频率 (<span class="hljs-reserved">default</span> <span class="hljs-number">1000</span>), * <span class="hljs-property">@param</span> {Boolean|Function} factory.log * <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span> <span class="hljs-keyword">or</span> <span class="hljs-reserved">function</span> 如果为<span class="hljs-literal">true</span>,log,info,verbose,信息会被传送到<span class="hljs-built_in">console</span>.log(<span class="hljs-string">""</span>)中,如果为<span class="hljs-reserved">function</span>,则需要两个参数 * log string * log level (<span class="hljs-string">'verbose'</span>, <span class="hljs-string">'info'</span>, <span class="hljs-string">'warn'</span>, <span class="hljs-string">'error'</span>) * <span class="hljs-property">@param</span> {Number} factory.priorityRange * int <span class="hljs-number">1</span> to x ,如果没有资源可使用,将根据工厂的优先级,依次从工厂队列中寻求资源。默认工厂优先级为<span class="hljs-number">1</span> * <span class="hljs-property">@param</span> {RefreshIdle} factory.refreshIdle * 默认为<span class="hljs-literal">true</span> ,默认情况先选择空闲资源被销毁后重新创建,时间即为超时时间。 * <span class="hljs-property">@param</span> {Bool} [factory.returnToHead=<span class="hljs-literal">false</span>] * 默认为<span class="hljs-literal">false</span>,如果为真,那么每次资源 * 返回到available对象数组的头部那么下一次获取的资源就为该数组的的第一个资源,这样就将资源队列变成了资源栈了 **/ <span class="hljs-reserved">function</span> Pool (factory) { <span class="hljs-keyword">if</span> (!(<span class="hljs-keyword">this</span> <span class="hljs-keyword">instanceof</span> Pool)) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Pool(factory) } <span class="hljs-keyword">if</span> (factory.validate && factory.validateAsync) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error(<span class="hljs-string">'Only one of validate or validateAsync may be specified'</span>) } <span class="hljs-regexp">//</span> defaults,默认设置 factory.idleTimeoutMillis = factory.idleTimeoutMillis || <span class="hljs-number">30000</span> factory.returnToHead = factory.returnToHead || <span class="hljs-literal">false</span> factory.refreshIdle = (<span class="hljs-string">'refreshIdle'</span> <span class="hljs-keyword">in</span> factory) ? factory.refreshIdle : <span class="hljs-literal">true</span> factory.reapInterval = factory.reapIntervalMillis || <span class="hljs-number">1000</span> factory.priorityRange = factory.priorityRange || <span class="hljs-number">1</span> factory.validate = factory.validate || <span class="hljs-reserved">function</span> () { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> } factory.max = parseInt(factory.max, <span class="hljs-number">10</span>) factory.min = parseInt(factory.min, <span class="hljs-number">10</span>) factory.max = Math.max(isNaN(factory.max) ? <span class="hljs-number">1</span> : factory.max, <span class="hljs-number">1</span>) factory.min = Math.min(isNaN(factory.min) ? <span class="hljs-number">0</span> : factory.min, factory.max - <span class="hljs-number">1</span>) <span class="hljs-keyword">this</span>._factory = factory <span class="hljs-keyword">this</span>._inUseObjects = []<span class="hljs-regexp">/*正在使用的资源*/</span> <span class="hljs-keyword">this</span>._draining = <span class="hljs-literal">false</span> <span class="hljs-keyword">this</span>._waitingClients = <span class="hljs-keyword">new</span> PriorityQueue(factory.priorityRange) <span class="hljs-regexp">/*优先级队列*/</span> <span class="hljs-keyword">this</span>._availableObjects = [] <span class="hljs-regexp">/*可用的资源*/</span> <span class="hljs-keyword">this</span>._count = <span class="hljs-number">0</span> /*引用计数*/ <span class="hljs-keyword">this</span>._removeIdleTimer = <span class="hljs-literal">null</span> <span class="hljs-keyword">this</span>._removeIdleScheduled = <span class="hljs-literal">false</span> <span class="hljs-regexp">//</span> create initial resources (<span class="hljs-keyword">if</span> factory.min > <span class="hljs-number">0</span>) <span class="hljs-keyword">this</span>._ensureMinimum()<span class="hljs-regexp">/*此处即为保证资源池中存在最少并发数资源*/</span> }</code>
上述代码的最后一句写明,该方法是用来保证资源池中存在最少并发数资源,那么来看下这个方法是如何实现的。这个也是个人学习源码的一点经验。
Pool.prototype._ensureMinimum 保证最小并发数
私有方法
实现代码就几行
<code class="hljs javascript has-numbering">Pool.prototype._ensureMinimum = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_ensureMinimum</span> <span class="hljs-params">()</span> {</span> <span class="hljs-keyword">var</span> i, diff <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._draining && (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.min)) { diff = <span class="hljs-keyword">this</span>._factory.min - <span class="hljs-keyword">this</span>._count <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i < diff; i++) { <span class="hljs-keyword">this</span>._createResource() } } }</code>
* ___* 上述代码中,如果没有将资源池排干或者当前资源计数小于最小并发数,那么将根据差值的个数构造相应多的资源。
那么来看下如何创建资源的:
Pool.prototype._createResource 创建资源
私有方法
先不看这个函数的具体实现,首先根据已经得到的知识,可以得到,至少创建一个资源,引用数加1,往_inUseObjects中push一个资源,还有就是打印日志等。
<code class="hljs javascript has-numbering">Pool.prototype._createResource = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_createResource</span> <span class="hljs-params">()</span> {</span> <span class="hljs-keyword">this</span>._count += <span class="hljs-number">1</span> <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'createResource() - creating obj - count='</span> + <span class="hljs-keyword">this</span>._count + <span class="hljs-string">' min='</span> + <span class="hljs-keyword">this</span>._factory.min + <span class="hljs-string">' max='</span> + <span class="hljs-keyword">this</span>._factory.max, <span class="hljs-string">'verbose'</span>) <span class="hljs-keyword">var</span> self = <span class="hljs-keyword">this</span> <span class="hljs-keyword">this</span>._factory.create(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span> <span class="hljs-keyword">var</span> err, obj <span class="hljs-comment">//从优先级队列中弹出一个Clinet客户应用</span> <span class="hljs-keyword">var</span> clientCb = self._waitingClients.dequeue() <span class="hljs-keyword">if</span> (<span class="hljs-built_in">arguments</span>.length > <span class="hljs-number">1</span>) { err = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] obj = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">1</span>] } <span class="hljs-keyword">else</span> { err = (<span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) ? <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] : <span class="hljs-literal">null</span> obj = (<span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) ? <span class="hljs-literal">null</span> : <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>] } <span class="hljs-keyword">if</span> (err) { self._count -= <span class="hljs-number">1</span> <span class="hljs-comment">//错误则-1 </span> <span class="hljs-keyword">if</span> (self._count < <span class="hljs-number">0</span>) self._count = <span class="hljs-number">0</span> <span class="hljs-keyword">if</span> (clientCb) { clientCb(err, obj) } process.nextTick(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span> self._dispense() <span class="hljs-comment">//下次循环事件中_dispense()很关键</span> }) } <span class="hljs-keyword">else</span> { self._inUseObjects.push(obj) <span class="hljs-comment">//push一个资源</span> <span class="hljs-keyword">if</span> (clientCb) { clientCb(err, obj) } <span class="hljs-keyword">else</span> { self.release(obj)<span class="hljs-comment">//错则释放</span> } } }) }</code>
Pool.prototype._dispense 工作
私有方法
这个方法用来:获取一个client使其工作,并且清理资源池里的空闲资源
- 如果有要连接的client正在等待,则将client后进先出(LIFO),并执行回调函数。
- 如果没有client等待,则尝试构造一个client,不超过最大连接数
- 如果构造的client超过了最大值,则将这个client加入等待队列中
<code class="hljs javascript has-numbering">Pool.prototype._dispense = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dispense</span> <span class="hljs-params">()</span> {</span> ... ... <span class="hljs-keyword">var</span> waitingCount = <span class="hljs-keyword">this</span>._waitingClients.size() <span class="hljs-keyword">if</span> (waitingCount > <span class="hljs-number">0</span>) { <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._factory.validateAsync) { doWhileAsync(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span> <span class="hljs-keyword">return</span> self._availableObjects.length > <span class="hljs-number">0</span> }, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(next)</span> {</span> objWithTimeout = self._availableObjects[<span class="hljs-number">0</span>] self._factory.validateAsync(objWithTimeout.obj, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(valid)</span> {</span> <span class="hljs-keyword">if</span> (!valid) { self.destroy(objWithTimeout.obj) next() } <span class="hljs-keyword">else</span> { self._availableObjects.shift()<span class="hljs-comment">//移出</span> self._inUseObjects.push(objWithTimeout.obj) clientCb = self._waitingClients.dequeue() clientCb(err, objWithTimeout.obj)<span class="hljs-comment">//回调</span> } }) }, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> {</span> <span class="hljs-keyword">if</span> (self._count < self._factory.max) { self._createResource() } }) <span class="hljs-keyword">return</span> } <span class="hljs-keyword">while</span> (<span class="hljs-keyword">this</span>._availableObjects.length > <span class="hljs-number">0</span>) { <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'dispense() - reusing obj'</span>, <span class="hljs-string">'verbose'</span>) objWithTimeout = <span class="hljs-keyword">this</span>._availableObjects[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>._factory.validate(objWithTimeout.obj)) { <span class="hljs-keyword">this</span>.destroy(objWithTimeout.obj) <span class="hljs-keyword">continue</span> } <span class="hljs-keyword">this</span>._availableObjects.shift() <span class="hljs-keyword">this</span>._inUseObjects.push(objWithTimeout.obj) clientCb = <span class="hljs-keyword">this</span>._waitingClients.dequeue() <span class="hljs-keyword">return</span> clientCb(err, objWithTimeout.obj) } <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.max) { <span class="hljs-keyword">this</span>._createResource() } } }</code>
上述代码可能不好理解,因为用到一个函数doWhileAsync
<code class="hljs lua has-numbering"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doWhileAsync</span> <span class="hljs-params">(conditionFn, iterateFn, callbackFn)</span></span> { var <span class="hljs-built_in">next</span> = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span></span> { <span class="hljs-keyword">if</span> (conditionFn()) { iterateFn(<span class="hljs-built_in">next</span>) } <span class="hljs-keyword">else</span> { callbackFn() } } <span class="hljs-built_in">next</span>() }</code>
所以根据上述的方法,可以得到_dispense中,如果self._availableObjects.length大于0,那么执行第二个函数,该函数从availableObjects中获取一个资源,并将其放入inUseObjects中,然后从client等待队列中选取一个进行回调,并进行递归调用。直到没有可用资源,最后执行第三个函数,就是继续创造资源。
Pool.prototype.acquire从资源池中获取资源
<code class="hljs javascript has-numbering">Pool.prototype.acquire = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">acquire</span> <span class="hljs-params">(callback, priority)</span> {</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._draining) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'pool is draining and cannot accept work'</span>) } <span class="hljs-comment">回调函数和优先级入队列,在变量clientCb中执行回调</span> <span class="hljs-keyword">this</span>._waitingClients.enqueue(callback, priority) <span class="hljs-keyword">this</span>._dispense()<span class="hljs-comment">//回调就在此处执行,使client执行。</span> <span class="hljs-keyword">return</span> (<span class="hljs-keyword">this</span>._count < <span class="hljs-keyword">this</span>._factory.max) }</code>
Pool.prototype.release将资源返回到资源池中
<code class="hljs javascript has-numbering">Pool.prototype.release = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">release</span> <span class="hljs-params">(obj)</span> {</span> <span class="hljs-comment">//如果在可用资源对象中已经存在了这样的obj,那么说明资源已经被回收,而这个release被调用了多次。那么不处理,只打印日志</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._availableObjects.some(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(objWithTimeout)</span> {</span> <span class="hljs-keyword">return</span> (objWithTimeout.obj === obj) })) { <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'release called twice for the same resource: '</span> + (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>().stack), <span class="hljs-string">'error'</span>) <span class="hljs-keyword">return</span> } <span class="hljs-comment">//判断要释放的资源是否在in use对象数组中,如果存在则remove</span> <span class="hljs-keyword">var</span> index = <span class="hljs-keyword">this</span>._inUseObjects.indexOf(obj) <span class="hljs-keyword">if</span> (index < <span class="hljs-number">0</span>) { <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'attempt to release an invalid resource: '</span> + (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>().stack), <span class="hljs-string">'error'</span>) <span class="hljs-keyword">return</span> } <span class="hljs-comment">// this._log("return to pool")</span> <span class="hljs-keyword">this</span>._inUseObjects.splice(index, <span class="hljs-number">1</span>)<span class="hljs-comment">//在正在使用的对象数组中删除</span> <span class="hljs-keyword">var</span> objWithTimeout = { obj: obj, timeout: (<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime() + <span class="hljs-keyword">this</span>._factory.idleTimeoutMillis) } <span class="hljs-comment">//是否返回到available对象数组的头部</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._factory.returnToHead) { <span class="hljs-comment">//从0开始,不删除项目(0),在头中添加objWithTimeoutd对象</span> <span class="hljs-keyword">this</span>._availableObjects.splice(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, objWithTimeout) } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">this</span>._availableObjects.push(objWithTimeout)<span class="hljs-comment">//尾部添加</span> } <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'timeout: '</span> + objWithTimeout.timeout, <span class="hljs-string">'verbose'</span>) <span class="hljs-keyword">this</span>._dispense() <span class="hljs-comment">//clean up idles items</span> <span class="hljs-keyword">this</span>._scheduleRemoveIdle()<span class="hljs-comment">//移出多余的idle资源,因为资源返回了,故可能需要,将idle资源回收。</span> }</code>
<code class="hljs cs has-numbering"><span class="hljs-keyword">this</span>._scheduleRemoveIdle()</code>
此方法不是重点,但是通过查看源码可以得知,如果设置是this._factory.reapInterval idle资源回收频率,那么模块将在Timeout时间内执行._removeIdle()函数,该函数的执行就是先获取需要remove的资源,放入到数组toRemove中,然后逐一调用this.destroy(toRemove[i]);注意remove的资源个数应为当前引用个数-最小并发数。
Pool.prototype.drain
<code class="hljs scala has-numbering"><span class="hljs-javadoc">/** * 不允许任何新请求,和已请求分离 * * <span class="hljs-javadoctag">@param</span> {Function} callback * 可选,如果所有的操作做完,所有的clients断开连接则执行回调函数 */</span> Pool.prototype.drain = function drain (callback) { ... <span class="hljs-keyword">this</span>._draining = <span class="hljs-keyword">true</span> <span class="hljs-keyword">var</span> check = function () { <span class="hljs-keyword">if</span> (self._waitingClients.size() > <span class="hljs-number">0</span>) { <span class="hljs-comment">// wait until all client requests have been satisfied.</span> setTimeout(check, <span class="hljs-number">100</span>) } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (self._availableObjects.length !== self._count) { <span class="hljs-comment">// wait until all objects have been released.</span> setTimeout(check, <span class="hljs-number">100</span>) } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (callback) { callback() } } check() }</code>
上述代码,就是一直在检查一直在检查,检查好了,执行回调操作
<code class="hljs javascript has-numbering">pool.drain(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> {</span> pool.destroyAllNow(); });</code>
最后来看一下:
Pool.prototype.destroyAllNow 清空所有连接
<code class="hljs javascript has-numbering">Pool.prototype.destroyAllNow = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">destroyAllNow</span> <span class="hljs-params">(callback)</span> {</span> <span class="hljs-keyword">this</span>._log(<span class="hljs-string">'force destroying all objects'</span>, <span class="hljs-string">'info'</span>) <span class="hljs-keyword">var</span> willDie = <span class="hljs-keyword">this</span>._availableObjects <span class="hljs-keyword">this</span>._availableObjects = [] <span class="hljs-comment">//清空</span> <span class="hljs-keyword">var</span> obj = willDie.shift() <span class="hljs-keyword">while</span> (obj !== <span class="hljs-literal">null</span> && obj !== <span class="hljs-literal">undefined</span>) { <span class="hljs-keyword">this</span>.destroy(obj.obj) obj = willDie.shift() } <span class="hljs-keyword">this</span>._removeIdleScheduled = <span class="hljs-literal">false</span> clearTimeout(<span class="hljs-keyword">this</span>._removeIdleTimer) <span class="hljs-keyword">if</span> (callback) { callback() } }</code>
有了前面代码的详细解释,这里的代码就能一看就懂了。
总结
- 内部使用了优先级队列,看了源码,只是几个简单的入队和出队等方法,故没有详细阐述,若有兴趣,可以查看源码学习之
- 若有错误,请一定要指出,相互学习。