• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7/**
8 * @class FunctionSequence to invoke steps in sequence
9 *
10 * @param {string} name                // TODO(JSDOC).
11 * @param {Array} steps                array of functions to invoke in sequence.
12 * @param {Object} logger              logger.
13 * @param {function} callback          callback to invoke on success.
14 * @param {function} failureCallback   callback to invoke on failure.
15 * @constructor
16 */
17function FunctionSequence(name, steps, logger, callback, failureCallback) {
18  // Private variables hidden in closure
19  this.currentStepIdx_ = -1;
20  this.failed_ = false;
21  this.steps_ = steps;
22  this.callback_ = callback;
23  this.failureCallback_ = failureCallback;
24  this.logger = logger;
25  this.name = name;
26
27  this.onError = this.onError_.bind(this);
28  this.finish = this.finish_.bind(this);
29  this.nextStep = this.nextStep_.bind(this);
30  this.apply = this.apply_.bind(this);
31}
32
33/**
34 * Sets new callback
35 *
36 * @param {function} callback new callback to call on succeed.
37 */
38FunctionSequence.prototype.setCallback = function(callback) {
39    this.callback_ = callback;
40};
41
42/**
43 * Sets new error callback
44 *
45 * @param {function} failureCallback new callback to call on failure.
46 */
47FunctionSequence.prototype.setFailureCallback = function(failureCallback) {
48    this.failureCallback_ = failureCallback;
49};
50
51
52/**
53 * Error handling function, which traces current error step, stops sequence
54 * advancing and fires error callback.
55 *
56 * @param {string} err Error message.
57 * @private
58 */
59FunctionSequence.prototype.onError_ = function(err) {
60  this.logger.vlog('Failed step: ' + this.steps_[this.currentStepIdx_].name +
61                   ': ' + err);
62  if (!this.failed_) {
63    this.failed_ = true;
64    this.failureCallback_(err);
65  }
66};
67
68/**
69 * Finishes sequence processing and jumps to the last step.
70 * This method should not be used externally. In external
71 * cases should be used finish function, which is defined in closure and thus
72 * has access to internal variables of functionsequence.
73 * @private
74 */
75FunctionSequence.prototype.finish_ = function() {
76  if (!this.failed_ && this.currentStepIdx_ < this.steps_.length) {
77    this.currentStepIdx_ = this.steps_.length;
78    this.callback_();
79  }
80};
81
82/**
83 * Advances to next step.
84 * This method should not be used externally. In external
85 * cases should be used nextStep function, which is defined in closure and thus
86 * has access to internal variables of functionsequence.
87 * @private
88 * @param {...} var_args  // TODO(JSDOC).
89 */
90FunctionSequence.prototype.nextStep_ = function(var_args) {
91  if (this.failed_) {
92    return;
93  }
94
95  if (++this.currentStepIdx_ >= this.steps_.length) {
96    this.logger.vlog('Sequence ended');
97    this.callback_.apply(this, arguments);
98  } else {
99    this.logger.vlog('Attempting to start step [' +
100                     this.steps_[this.currentStepIdx_].name +
101                     ']');
102    try {
103      this.steps_[this.currentStepIdx_].apply(this, arguments);
104    } catch (e) {
105      this.onError(e.toString());
106    }
107  }
108};
109
110/**
111 * This function should be called only once on start, so start sequence pipeline
112 * @param {...} var_args  // TODO(JSDOC).
113 */
114FunctionSequence.prototype.start = function(var_args) {
115  if (this.started) {
116    throw new Error('"Start" method of FunctionSequence was called twice');
117  }
118
119  this.logger.log('Starting sequence with ' + arguments.length + ' arguments');
120
121  this.started = true;
122  this.nextStep.apply(this, arguments);
123};
124
125/**
126 * Add Function object mimics to FunctionSequence
127 * @private
128 * @param {*} obj  // TODO(JSDOC).
129 * @param {Array.*} args  // TODO(JSDOC).
130 */
131FunctionSequence.prototype.apply_ = function(obj, args) {
132  this.start.apply(this, args);
133};
134