michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let EXPORTED_SYMBOLS = [ michael@0: "AsyncRunner", michael@0: ]; michael@0: michael@0: const { interfaces: Ci, classes: Cc } = Components; michael@0: michael@0: function AsyncRunner(callbacks) { michael@0: this._callbacks = callbacks; michael@0: this._iteratorQueue = []; michael@0: michael@0: // This catches errors reported to the console, e.g., via Cu.reportError. michael@0: Cc["@mozilla.org/consoleservice;1"]. michael@0: getService(Ci.nsIConsoleService). michael@0: registerListener(this); michael@0: } michael@0: michael@0: AsyncRunner.prototype = { michael@0: michael@0: appendIterator: function AR_appendIterator(iter) { michael@0: this._iteratorQueue.push(iter); michael@0: }, michael@0: michael@0: next: function AR_next(/* ... */) { michael@0: if (!this._iteratorQueue.length) { michael@0: this.destroy(); michael@0: this._callbacks.done(); michael@0: return; michael@0: } michael@0: michael@0: // send() discards all arguments after the first, so there's no choice here michael@0: // but to send only one argument to the yielder. michael@0: let args = [arguments.length <= 1 ? arguments[0] : Array.slice(arguments)]; michael@0: try { michael@0: var val = this._iteratorQueue[0].send.apply(this._iteratorQueue[0], args); michael@0: } michael@0: catch (err if err instanceof StopIteration) { michael@0: this._iteratorQueue.shift(); michael@0: this.next(); michael@0: return; michael@0: } michael@0: catch (err) { michael@0: this._callbacks.error(err); michael@0: } michael@0: michael@0: // val is truthy => call next michael@0: // val is an iterator => prepend it to the queue and start on it michael@0: if (val) { michael@0: if (typeof(val) != "boolean") michael@0: this._iteratorQueue.unshift(val); michael@0: this.next(); michael@0: } michael@0: }, michael@0: michael@0: destroy: function AR_destroy() { michael@0: Cc["@mozilla.org/consoleservice;1"]. michael@0: getService(Ci.nsIConsoleService). michael@0: unregisterListener(this); michael@0: this.destroy = function AR_alreadyDestroyed() {}; michael@0: }, michael@0: michael@0: observe: function AR_consoleServiceListener(msg) { michael@0: if (msg instanceof Ci.nsIScriptError && michael@0: !(msg.flags & Ci.nsIScriptError.warningFlag)) michael@0: { michael@0: this._callbacks.consoleError(msg); michael@0: } michael@0: }, michael@0: };