fcs
2025-04-10 0163870d662dc5b7d69ceff977490ede594f7d82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
'use strict'
 
// like a promise
// if a value is added, it is queued until the first then()
// if then() is called before a value is available,
//   the returned promise is deferred
//   and queued up for later resolution eg when the next value is available or the
//   Result is completed.
 
const CLOSED = Promise.resolve()
 
module.exports = class Result {
  constructor () {
    this._isClosed = false
    this._pendingPromises = []
    this._pendingVals = []
 
    // TODO Nice to have ...array argument -> add()
  }
 
  add (val) {
    if (this.isClosed) {
      throw new Error('cannot add() to a closed Result')
    }
 
    if (this._pendingPromises.length > 0) {
      this._finishPromises(val)
    } else {
      this._pendingVals.push(val)
    }
  }
 
  get isClosed () {
    return this._isClosed
  }
 
  get hasValues () {
    return this._pendingVals.length > 0
  }
 
  /**
   * Requests the next value, wrapped in a promise.
   * If no more values are available and the Result
   * is closed, a Promise resolved to undefined is returned.
   * Else, the returned promise will resolve or reject
   * when the next value is added.
   *
   * @param {Function} res
   * @param {Function} rej
   * @return {Promise}
   */
  then (res, rej) {
    if (this.hasValues) {
      const val = this._pendingVals.shift()
      const method = val instanceof Error ? 'reject' : 'resolve'
      return Promise[method](val).then(res, rej)
    }
 
    if (this.isClosed) {
      // no more values will ever be available
      return CLOSED.then(res, rej)
    }
 
    const p = new Promise((resolve, reject) => {
      this._pendingPromises.push({ resolve, reject })
    })
 
    return p.then(res, rej)
  }
 
  close (val) {
    this.add(val)
    this._isClosed = true
  }
 
  _finishPromises (val) {
    const method = val instanceof Error ? 'reject' : 'resolve'
 
    let promise
    while ((promise = this._pendingPromises.shift())) {
      promise[method](val)
    }
  }
}