utils: rewrite async object.
This commit is contained in:
parent
d088412380
commit
06b35d4ab2
@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var utils = require('../utils/utils');
|
var utils = require('./utils');
|
||||||
var co = require('../utils/co');
|
var co = require('./co');
|
||||||
|
var Locker = require('./locker');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
@ -25,10 +26,11 @@ function AsyncObject() {
|
|||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
|
this._asyncLock = new Locker();
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.closing = false;
|
this.closing = false;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.locker = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.inherits(AsyncObject, EventEmitter);
|
utils.inherits(AsyncObject, EventEmitter);
|
||||||
@ -39,18 +41,23 @@ utils.inherits(AsyncObject, EventEmitter);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
AsyncObject.prototype.open = co(function* open() {
|
AsyncObject.prototype.open = co(function* open() {
|
||||||
var err, unlock;
|
var unlock = yield this._asyncLock.lock();
|
||||||
|
try {
|
||||||
|
return yield this.__open();
|
||||||
|
} finally {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
assert(!this.closing, 'Cannot open while closing.');
|
/**
|
||||||
|
* Open the object (without a lock).
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
AsyncObject.prototype.__open = co(function* open() {
|
||||||
if (this.loaded)
|
if (this.loaded)
|
||||||
return yield co.wait();
|
return;
|
||||||
|
|
||||||
if (this.loading)
|
|
||||||
return yield this._onOpen();
|
|
||||||
|
|
||||||
if (this.locker)
|
|
||||||
unlock = yield this.locker.lock();
|
|
||||||
|
|
||||||
this.emit('preopen');
|
this.emit('preopen');
|
||||||
|
|
||||||
@ -59,25 +66,15 @@ AsyncObject.prototype.open = co(function* open() {
|
|||||||
try {
|
try {
|
||||||
yield this._open();
|
yield this._open();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield co.wait();
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this._error('open', err);
|
this.emit('error', e);
|
||||||
if (unlock)
|
throw e;
|
||||||
unlock();
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
this.emit('open');
|
|
||||||
|
|
||||||
if (unlock)
|
this.emit('open');
|
||||||
unlock();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,45 +83,40 @@ AsyncObject.prototype.open = co(function* open() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
AsyncObject.prototype.close = co(function* close() {
|
AsyncObject.prototype.close = co(function* close() {
|
||||||
var unlock, err;
|
var unlock = yield this._asyncLock.lock();
|
||||||
|
try {
|
||||||
|
return yield this.__close();
|
||||||
|
} finally {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
assert(!this.loading, 'Cannot close while loading.');
|
/**
|
||||||
|
* Close the object (without a lock).
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
AsyncObject.prototype.__close = co(function* close() {
|
||||||
if (!this.loaded)
|
if (!this.loaded)
|
||||||
return yield co.wait();
|
return;
|
||||||
|
|
||||||
if (this.closing)
|
|
||||||
return yield this._onClose();
|
|
||||||
|
|
||||||
if (this.locker)
|
|
||||||
unlock = yield this.locker.lock();
|
|
||||||
|
|
||||||
this.emit('preclose');
|
this.emit('preclose');
|
||||||
|
|
||||||
this.closing = true;
|
this.closing = true;
|
||||||
this.loaded = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield this._close();
|
yield this._close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield co.wait();
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
this.closing = false;
|
this.closing = false;
|
||||||
this._error('close', err);
|
this.emit('error', e);
|
||||||
if (unlock)
|
throw e;
|
||||||
unlock();
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closing = false;
|
this.closing = false;
|
||||||
this.emit('close');
|
this.loaded = false;
|
||||||
|
|
||||||
if (unlock)
|
this.emit('close');
|
||||||
unlock();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,25 +127,6 @@ AsyncObject.prototype.close = co(function* close() {
|
|||||||
|
|
||||||
AsyncObject.prototype.destroy = AsyncObject.prototype.close;
|
AsyncObject.prototype.destroy = AsyncObject.prototype.close;
|
||||||
|
|
||||||
/**
|
|
||||||
* Emit an error for `open` or `close` listeners.
|
|
||||||
* @private
|
|
||||||
* @param {String} event
|
|
||||||
* @param {Error} err
|
|
||||||
*/
|
|
||||||
|
|
||||||
AsyncObject.prototype._error = function _error(event, err) {
|
|
||||||
var listeners = this.listeners(event);
|
|
||||||
var i;
|
|
||||||
|
|
||||||
this.removeAllListeners(event);
|
|
||||||
|
|
||||||
for (i = 0; i < listeners.length; i++)
|
|
||||||
listeners[i](err);
|
|
||||||
|
|
||||||
this.emit('error', err);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the object.
|
* Initialize the object.
|
||||||
* @private
|
* @private
|
||||||
@ -174,32 +147,6 @@ AsyncObject.prototype._close = function _close(callback) {
|
|||||||
throw new Error('Abstract method.');
|
throw new Error('Abstract method.');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for open event.
|
|
||||||
* @private
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
AsyncObject.prototype._onOpen = function _onOpen() {
|
|
||||||
var self = this;
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
return self.once('open', resolve);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for close event.
|
|
||||||
* @private
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
AsyncObject.prototype._onClose = function _onClose() {
|
|
||||||
var self = this;
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
return self.once('close', resolve);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user