tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Promise-subclassing.html (7745B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title></title>
      4 <script src=/resources/testharness.js></script>
      5 <script src=/resources/testharnessreport.js></script>
      6 <script>
      7 
      8 var theLog = [];
      9 var speciesGets = 0;
     10 var speciesCalls = 0;
     11 var constructorCalls = 0;
     12 var constructorGets = 0;
     13 var resolveCalls = 0;
     14 var rejectCalls = 0;
     15 var thenCalls = 0;
     16 var catchCalls = 0;
     17 var allCalls = 0;
     18 var raceCalls = 0;
     19 var nextCalls = 0;
     20 
     21 function takeLog() {
     22  var oldLog = theLog;
     23  theLog = [];
     24  speciesGets = speciesCalls = constructorCalls = resolveCalls =
     25    rejectCalls = thenCalls = catchCalls = allCalls = raceCalls =
     26    nextCalls = constructorGets = 0;
     27  return oldLog;
     28 }
     29 
     30 function clearLog() {
     31  takeLog();
     32 }
     33 
     34 function log(str) {
     35  theLog.push(str);
     36 }
     37 
     38 class LoggingPromise extends Promise {
     39  constructor(func) {
     40    super(func);
     41    Object.defineProperty(this, "constructor",
     42                          {
     43                            get: function() {
     44                              ++constructorGets;
     45                              log(`Constructor get ${constructorGets}`);
     46                              return Object.getPrototypeOf(this).constructor;
     47                            }
     48                          });
     49    ++constructorCalls;
     50    log(`Constructor ${constructorCalls}`);
     51  }
     52 
     53  static get [Symbol.species]() {
     54    ++speciesGets;
     55    log(`Species get ${speciesGets}`);
     56    return LoggingSpecies;
     57  }
     58 
     59  static resolve(val) {
     60    ++resolveCalls;
     61    log(`Resolve ${resolveCalls}`);
     62    return super.resolve(val);
     63  }
     64 
     65  static reject(val) {
     66    ++rejectCalls;
     67    log(`Reject ${rejectCalls}`);
     68    return super.reject(val);
     69  }
     70 
     71  then(resolve, reject) {
     72    ++thenCalls;
     73    log(`Then ${thenCalls}`);
     74    return super.then(resolve, reject);
     75  }
     76 
     77  catch(handler) {
     78    ++catchCalls;
     79    log(`Catch ${catchCalls}`);
     80    return super.catch(handler);
     81  }
     82 
     83  static all(val) {
     84    ++allCalls;
     85    log(`All ${allCalls}`);
     86    return super.all(val);
     87  }
     88 
     89  static race(val) {
     90    ++raceCalls;
     91    log(`Race ${raceCalls}`);
     92    return super.race(val);
     93  }
     94 }
     95 
     96 class LoggingIterable {
     97  constructor(array) {
     98    this.iter = array[Symbol.iterator]();
     99  }
    100 
    101  get [Symbol.iterator]() { return () => this }
    102 
    103  next() {
    104    ++nextCalls;
    105    log(`Next ${nextCalls}`);
    106    return this.iter.next();
    107  }
    108 }
    109 
    110 class LoggingSpecies extends LoggingPromise {
    111  constructor(func) {
    112    ++speciesCalls;
    113    log(`Species call ${speciesCalls}`);
    114    super(func)
    115  }
    116 }
    117 
    118 class SpeciesLessPromise extends LoggingPromise {
    119  static get [Symbol.species]() {
    120    return undefined;
    121  }
    122 }
    123 
    124 promise_test(function testBasicConstructor() {
    125  var p = new LoggingPromise((resolve) => resolve(5));
    126  var log = takeLog();
    127  assert_array_equals(log, ["Constructor 1"]);
    128  assert_true(p instanceof LoggingPromise);
    129  return p.then(function(arg) {
    130    assert_equals(arg, 5);
    131  });
    132 }, "Basic constructor behavior");
    133 
    134 promise_test(function testPromiseRace() {
    135  clearLog();
    136  var p = LoggingPromise.race(new LoggingIterable([1, 2]));
    137  var log = takeLog();
    138  assert_array_equals(log, ["Race 1", "Constructor 1",
    139                            "Next 1", "Resolve 1", "Constructor 2",
    140                            "Then 1", "Constructor get 1", "Species get 1", "Species call 1", "Constructor 3",
    141                            "Next 2", "Resolve 2", "Constructor 4",
    142                            "Then 2", "Constructor get 2", "Species get 2", "Species call 2", "Constructor 5",
    143                            "Next 3"]);
    144  assert_true(p instanceof LoggingPromise);
    145  return p.then(function(arg) {
    146    assert_in_array(arg, [1, 2]);
    147  });
    148 }, "Promise.race behavior");
    149 
    150 promise_test(function testPromiseRaceNoSpecies() {
    151  clearLog();
    152  var p = SpeciesLessPromise.race(new LoggingIterable([1, 2]));
    153  var log = takeLog();
    154  assert_array_equals(log, ["Race 1", "Constructor 1",
    155                            "Next 1", "Resolve 1", "Constructor 2",
    156                            "Then 1", "Constructor get 1",
    157                            "Next 2", "Resolve 2", "Constructor 3",
    158                            "Then 2", "Constructor get 2",
    159                            "Next 3"]);
    160  assert_true(p instanceof SpeciesLessPromise);
    161  return p.then(function(arg) {
    162    assert_in_array(arg, [1, 2]);
    163  });
    164 }, "Promise.race without species behavior");
    165 
    166 promise_test(function testPromiseAll() {
    167  clearLog();
    168  var p = LoggingPromise.all(new LoggingIterable([1, 2]));
    169  var log = takeLog();
    170  assert_array_equals(log, ["All 1", "Constructor 1",
    171                            "Next 1", "Resolve 1", "Constructor 2",
    172                            "Then 1", "Constructor get 1", "Species get 1", "Species call 1", "Constructor 3",
    173                            "Next 2", "Resolve 2", "Constructor 4",
    174                            "Then 2", "Constructor get 2", "Species get 2", "Species call 2", "Constructor 5",
    175                            "Next 3"]);
    176  assert_true(p instanceof LoggingPromise);
    177  return p.then(function(arg) {
    178    assert_array_equals(arg, [1, 2]);
    179  });
    180 }, "Promise.all behavior");
    181 
    182 promise_test(function testPromiseResolve() {
    183  clearLog();
    184  var p = LoggingPromise.resolve(5);
    185  var log = takeLog();
    186  assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
    187  var q = LoggingPromise.resolve(p);
    188  assert_equals(p, q,
    189                "Promise.resolve with same constructor should preserve identity");
    190  log = takeLog();
    191  assert_array_equals(log, ["Resolve 1", "Constructor get 1"]);
    192 
    193  var r = Promise.resolve(p);
    194  log = takeLog();
    195  assert_array_equals(log, ["Constructor get 1"]);
    196  assert_not_equals(p, r,
    197                    "Promise.resolve with different constructor should " +
    198                    "create a new Promise instance (1)")
    199  var s = Promise.resolve(6);
    200  var u = LoggingPromise.resolve(s);
    201  log = takeLog();
    202  assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
    203  assert_not_equals(s, u,
    204                    "Promise.resolve with different constructor should " +
    205                    "create a new Promise instance (2)")
    206 
    207  Object.defineProperty(s, "constructor", { value: LoggingPromise });
    208  var v = LoggingPromise.resolve(s);
    209  log = takeLog();
    210  assert_array_equals(log, ["Resolve 1"]);
    211  assert_equals(v, s, "Faking the .constructor should work");
    212  assert_false(v instanceof LoggingPromise);
    213 
    214  var results = Promise.all([p, q, r, s, u, v]);
    215  return results.then(function(arg) {
    216    assert_array_equals(arg, [5, 5, 5, 6, 6, 6]);
    217  });
    218 }, "Promise.resolve behavior");
    219 
    220 promise_test(function testPromiseReject() {
    221  clearLog();
    222  var p = LoggingPromise.reject(5);
    223  var log = takeLog();
    224  assert_array_equals(log, ["Reject 1", "Constructor 1"]);
    225 
    226  return p.catch(function(arg) {
    227    assert_equals(arg, 5);
    228  });
    229 }, "Promise.reject behavior");
    230 
    231 promise_test(function testPromiseThen() {
    232  clearLog();
    233  var p = LoggingPromise.resolve(5);
    234  var log = takeLog();
    235  assert_array_equals(log, ["Resolve 1", "Constructor 1"]);
    236 
    237  var q = p.then((x) => x*x);
    238  log = takeLog();
    239  assert_array_equals(log, ["Then 1", "Constructor get 1", "Species get 1",
    240                            "Species call 1", "Constructor 1"]);
    241  assert_true(q instanceof LoggingPromise);
    242 
    243  return q.then(function(arg) {
    244    assert_equals(arg, 25);
    245  });
    246 }, "Promise.then behavior");
    247 
    248 promise_test(function testPromiseCatch() {
    249  clearLog();
    250  var p = LoggingPromise.reject(5);
    251  var log = takeLog();
    252  assert_array_equals(log, ["Reject 1", "Constructor 1"]);
    253 
    254  var q = p.catch((x) => x*x);
    255  log = takeLog();
    256  assert_array_equals(log, ["Catch 1", "Then 1", "Constructor get 1",
    257                            "Species get 1", "Species call 1", "Constructor 1"]);
    258  assert_true(q instanceof LoggingPromise);
    259 
    260  return q.then(function(arg) {
    261    assert_equals(arg, 25);
    262  });
    263 }, "Promise.catch behavior");
    264 
    265 </script>