Completed
Push — dev ( 86e7e0...f66596 )
by Fike
33s
created

timeout.js ➔ timeout   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 29
rs 8.5806

5 Functions

Rating   Name   Duplication   Size   Complexity  
A timeout.js ➔ ... ➔ wrapper.cancel 0 4 1
A timeout.js ➔ ... ➔ promise.cancel 0 1 1
A timeout.js ➔ ... ➔ callback 0 3 1
A timeout.js ➔ ... ➔ setTimeout 0 3 1
A timeout.js ➔ ... ➔ cancel 0 6 2
1
var Future = require('./Future').Future
2
3
/**
4
 * @class
5
 * @param {string} message
6
 */
7
function TimeoutException (message) {
8
  this.message = message || 'Timeout has exceeded'
9
  this.stack = (new Error()).stack
10
}
11
12
var _ = TimeoutException
13
14
_.prototype = Object.create(Error.prototype)
15
_.prototype.name = 'TimeoutException'
16
_.prototype.constructor = _
17
18
function CancellationException (message) {
19
  this.message = message || 'Promise has been cancelled'
20
  this.stack = (new Error()).stack
21
}
22
23
_ = CancellationException
24
_.prototype = Object.create(Error.prototype)
25
_.prototype.name = 'CancellationException'
26
_.prototype.constructor = _
27
28
/**
29
 * @interface ICancellablePromise
30
 * @template T
31
 * @extends Thenable.<T>
32
 */
33
34
/**
35
 * @function ICancellablePromise#cancel
36
 *
37
 * @param {boolean} [silent] Whether to cancel with CancellationException or
38
 * just pretend that nothing has happened
39
 *
40
 * @return ICancellablePromise The very same instance
41
 */
42
43
/**
44
 * @callback timeout~onTimeout
45
 *
46
 * @param {Function} resolve
47
 * @param {Function} reject
48
 */
49
50
/**
51
 * @param {Promise.<*>|Thenable.<*>} promise Promise to add time bound to
52
 * @param {int} [timeout] Timeout in milliseconds
53
 * @param {timeout~onTimeout|string} [callback] Callback to be run on timeout.
54
 *   If string is passed, it is used as a message in timeout exception.
55
 * @return {ICancellablePromise.<*>}
56
 */
57
function timeout (promise, timeout, callback) {
58
  if (typeof timeout !== 'number' || timeout < 0) {
59
    promise.cancel = function () { return promise }
60
    return promise
61
  }
62
  callback = callback || 'Timeout of ' + timeout + ' ms has exceeded'
63
  if (typeof callback === 'string') {
64
    var message = callback
65
    callback = function (_, reject) {
66
      reject(new TimeoutException(message))
67
    }
68
  }
69
  var wrapper = Future.wrap(promise)
70
  var bind = setTimeout(function () {
71
    callback(wrapper.resolve, wrapper.reject)
72
  }, timeout)
73
  var cancel = function (silent) {
74
    clearTimeout(bind)
75
    if (!silent) {
76
      wrapper.reject(new CancellationException())
77
    }
78
  }
79
  wrapper.then(cancel, cancel)
80
  wrapper.cancel = function (silent) {
81
    cancel(silent)
82
    return wrapper
83
  }
84
  return wrapper
85
}
86
87
/**
88
 * Delays processing of callback for specified time. If no callback is
89
 * given, returns empty promise that will resolve in specified time
90
 *
91
 * @param {int} time
92
 * @param {Function} [callback]
93
 *
94
 * @return {Thenable.<*>}
95
 */
96
function delay (time, callback) {
97
  callback = callback || function () {}
98
  var target = new Future()
99
  var resolve = function () {
100
    try {
101
      target.resolve(callback())
102
    } catch (e) {
103
      target.reject(e)
104
    }
105
  }
106
  var bind = setTimeout(resolve, time)
107
  target.cancel = function (silent) {
108
    clearTimeout(bind)
109
    silent ? resolve() : target.reject(new CancellationException())
110
    return target
111
  }
112
  return target
113
}
114
115
/**
116
 * Wraps given promise with another one which won't resolve earlier
117
 * than specified time.
118
 *
119
 * @param {Thenable.<*>} promise
120
 * @param {int} time Throttle time in milliseconds
121
 * @return {Thenable.<*>}
122
 */
123
function throttle (promise, time) {
124
  var delayed = delay(time)
125
  var target = delayed
126
    .then(function () {
127
      return promise
128
    })
129
  target.cancel = function (silent) {
130
    delayed.cancel(silent)
131
    return target
132
  }
133
  return target
134
}
135
136
module.exports = {
137
  timeout: timeout,
138
  delay: delay,
139
  throttle: throttle,
140
  TimeoutException: TimeoutException,
141
  CancellationException: CancellationException
142
}
143