Projekt

Obecné

Profil

Stáhnout (23.2 KB) Statistiky
| Větev: | Revize:
1
/** @license React v0.19.1
2
 * scheduler.development.js
3
 *
4
 * Copyright (c) Facebook, Inc. and its affiliates.
5
 *
6
 * This source code is licensed under the MIT license found in the
7
 * LICENSE file in the root directory of this source tree.
8
 */
9

    
10
'use strict';
11

    
12

    
13

    
14
if (process.env.NODE_ENV !== "production") {
15
  (function() {
16
'use strict';
17

    
18
var enableSchedulerDebugging = false;
19
var enableProfiling = true;
20

    
21
var requestHostCallback;
22
var requestHostTimeout;
23
var cancelHostTimeout;
24
var shouldYieldToHost;
25
var requestPaint;
26

    
27
if ( // If Scheduler runs in a non-DOM environment, it falls back to a naive
28
// implementation using setTimeout.
29
typeof window === 'undefined' || // Check if MessageChannel is supported, too.
30
typeof MessageChannel !== 'function') {
31
  // If this accidentally gets imported in a non-browser environment, e.g. JavaScriptCore,
32
  // fallback to a naive implementation.
33
  var _callback = null;
34
  var _timeoutID = null;
35

    
36
  var _flushCallback = function () {
37
    if (_callback !== null) {
38
      try {
39
        var currentTime = exports.unstable_now();
40
        var hasRemainingTime = true;
41

    
42
        _callback(hasRemainingTime, currentTime);
43

    
44
        _callback = null;
45
      } catch (e) {
46
        setTimeout(_flushCallback, 0);
47
        throw e;
48
      }
49
    }
50
  };
51

    
52
  var initialTime = Date.now();
53

    
54
  exports.unstable_now = function () {
55
    return Date.now() - initialTime;
56
  };
57

    
58
  requestHostCallback = function (cb) {
59
    if (_callback !== null) {
60
      // Protect against re-entrancy.
61
      setTimeout(requestHostCallback, 0, cb);
62
    } else {
63
      _callback = cb;
64
      setTimeout(_flushCallback, 0);
65
    }
66
  };
67

    
68
  requestHostTimeout = function (cb, ms) {
69
    _timeoutID = setTimeout(cb, ms);
70
  };
71

    
72
  cancelHostTimeout = function () {
73
    clearTimeout(_timeoutID);
74
  };
75

    
76
  shouldYieldToHost = function () {
77
    return false;
78
  };
79

    
80
  requestPaint = exports.unstable_forceFrameRate = function () {};
81
} else {
82
  // Capture local references to native APIs, in case a polyfill overrides them.
83
  var performance = window.performance;
84
  var _Date = window.Date;
85
  var _setTimeout = window.setTimeout;
86
  var _clearTimeout = window.clearTimeout;
87

    
88
  if (typeof console !== 'undefined') {
89
    // TODO: Scheduler no longer requires these methods to be polyfilled. But
90
    // maybe we want to continue warning if they don't exist, to preserve the
91
    // option to rely on it in the future?
92
    var requestAnimationFrame = window.requestAnimationFrame;
93
    var cancelAnimationFrame = window.cancelAnimationFrame; // TODO: Remove fb.me link
94

    
95
    if (typeof requestAnimationFrame !== 'function') {
96
      // Using console['error'] to evade Babel and ESLint
97
      console['error']("This browser doesn't support requestAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills');
98
    }
99

    
100
    if (typeof cancelAnimationFrame !== 'function') {
101
      // Using console['error'] to evade Babel and ESLint
102
      console['error']("This browser doesn't support cancelAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills');
103
    }
104
  }
105

    
106
  if (typeof performance === 'object' && typeof performance.now === 'function') {
107
    exports.unstable_now = function () {
108
      return performance.now();
109
    };
110
  } else {
111
    var _initialTime = _Date.now();
112

    
113
    exports.unstable_now = function () {
114
      return _Date.now() - _initialTime;
115
    };
116
  }
117

    
118
  var isMessageLoopRunning = false;
119
  var scheduledHostCallback = null;
120
  var taskTimeoutID = -1; // Scheduler periodically yields in case there is other work on the main
121
  // thread, like user events. By default, it yields multiple times per frame.
122
  // It does not attempt to align with frame boundaries, since most tasks don't
123
  // need to be frame aligned; for those that do, use requestAnimationFrame.
124

    
125
  var yieldInterval = 5;
126
  var deadline = 0; // TODO: Make this configurable
127

    
128
  {
129
    // `isInputPending` is not available. Since we have no way of knowing if
130
    // there's pending input, always yield at the end of the frame.
131
    shouldYieldToHost = function () {
132
      return exports.unstable_now() >= deadline;
133
    }; // Since we yield every frame regardless, `requestPaint` has no effect.
134

    
135

    
136
    requestPaint = function () {};
137
  }
138

    
139
  exports.unstable_forceFrameRate = function (fps) {
140
    if (fps < 0 || fps > 125) {
141
      // Using console['error'] to evade Babel and ESLint
142
      console['error']('forceFrameRate takes a positive int between 0 and 125, ' + 'forcing framerates higher than 125 fps is not unsupported');
143
      return;
144
    }
145

    
146
    if (fps > 0) {
147
      yieldInterval = Math.floor(1000 / fps);
148
    } else {
149
      // reset the framerate
150
      yieldInterval = 5;
151
    }
152
  };
153

    
154
  var performWorkUntilDeadline = function () {
155
    if (scheduledHostCallback !== null) {
156
      var currentTime = exports.unstable_now(); // Yield after `yieldInterval` ms, regardless of where we are in the vsync
157
      // cycle. This means there's always time remaining at the beginning of
158
      // the message event.
159

    
160
      deadline = currentTime + yieldInterval;
161
      var hasTimeRemaining = true;
162

    
163
      try {
164
        var hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime);
165

    
166
        if (!hasMoreWork) {
167
          isMessageLoopRunning = false;
168
          scheduledHostCallback = null;
169
        } else {
170
          // If there's more work, schedule the next message event at the end
171
          // of the preceding one.
172
          port.postMessage(null);
173
        }
174
      } catch (error) {
175
        // If a scheduler task throws, exit the current browser task so the
176
        // error can be observed.
177
        port.postMessage(null);
178
        throw error;
179
      }
180
    } else {
181
      isMessageLoopRunning = false;
182
    } // Yielding to the browser will give it a chance to paint, so we can
183
  };
184

    
185
  var channel = new MessageChannel();
186
  var port = channel.port2;
187
  channel.port1.onmessage = performWorkUntilDeadline;
188

    
189
  requestHostCallback = function (callback) {
190
    scheduledHostCallback = callback;
191

    
192
    if (!isMessageLoopRunning) {
193
      isMessageLoopRunning = true;
194
      port.postMessage(null);
195
    }
196
  };
197

    
198
  requestHostTimeout = function (callback, ms) {
199
    taskTimeoutID = _setTimeout(function () {
200
      callback(exports.unstable_now());
201
    }, ms);
202
  };
203

    
204
  cancelHostTimeout = function () {
205
    _clearTimeout(taskTimeoutID);
206

    
207
    taskTimeoutID = -1;
208
  };
209
}
210

    
211
function push(heap, node) {
212
  var index = heap.length;
213
  heap.push(node);
214
  siftUp(heap, node, index);
215
}
216
function peek(heap) {
217
  var first = heap[0];
218
  return first === undefined ? null : first;
219
}
220
function pop(heap) {
221
  var first = heap[0];
222

    
223
  if (first !== undefined) {
224
    var last = heap.pop();
225

    
226
    if (last !== first) {
227
      heap[0] = last;
228
      siftDown(heap, last, 0);
229
    }
230

    
231
    return first;
232
  } else {
233
    return null;
234
  }
235
}
236

    
237
function siftUp(heap, node, i) {
238
  var index = i;
239

    
240
  while (true) {
241
    var parentIndex = index - 1 >>> 1;
242
    var parent = heap[parentIndex];
243

    
244
    if (parent !== undefined && compare(parent, node) > 0) {
245
      // The parent is larger. Swap positions.
246
      heap[parentIndex] = node;
247
      heap[index] = parent;
248
      index = parentIndex;
249
    } else {
250
      // The parent is smaller. Exit.
251
      return;
252
    }
253
  }
254
}
255

    
256
function siftDown(heap, node, i) {
257
  var index = i;
258
  var length = heap.length;
259

    
260
  while (index < length) {
261
    var leftIndex = (index + 1) * 2 - 1;
262
    var left = heap[leftIndex];
263
    var rightIndex = leftIndex + 1;
264
    var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those.
265

    
266
    if (left !== undefined && compare(left, node) < 0) {
267
      if (right !== undefined && compare(right, left) < 0) {
268
        heap[index] = right;
269
        heap[rightIndex] = node;
270
        index = rightIndex;
271
      } else {
272
        heap[index] = left;
273
        heap[leftIndex] = node;
274
        index = leftIndex;
275
      }
276
    } else if (right !== undefined && compare(right, node) < 0) {
277
      heap[index] = right;
278
      heap[rightIndex] = node;
279
      index = rightIndex;
280
    } else {
281
      // Neither child is smaller. Exit.
282
      return;
283
    }
284
  }
285
}
286

    
287
function compare(a, b) {
288
  // Compare sort index first, then task id.
289
  var diff = a.sortIndex - b.sortIndex;
290
  return diff !== 0 ? diff : a.id - b.id;
291
}
292

    
293
// TODO: Use symbols?
294
var NoPriority = 0;
295
var ImmediatePriority = 1;
296
var UserBlockingPriority = 2;
297
var NormalPriority = 3;
298
var LowPriority = 4;
299
var IdlePriority = 5;
300

    
301
var runIdCounter = 0;
302
var mainThreadIdCounter = 0;
303
var profilingStateSize = 4;
304
var sharedProfilingBuffer =  // $FlowFixMe Flow doesn't know about SharedArrayBuffer
305
typeof SharedArrayBuffer === 'function' ? new SharedArrayBuffer(profilingStateSize * Int32Array.BYTES_PER_ELEMENT) : // $FlowFixMe Flow doesn't know about ArrayBuffer
306
typeof ArrayBuffer === 'function' ? new ArrayBuffer(profilingStateSize * Int32Array.BYTES_PER_ELEMENT) : null // Don't crash the init path on IE9
307
;
308
var profilingState =  sharedProfilingBuffer !== null ? new Int32Array(sharedProfilingBuffer) : []; // We can't read this but it helps save bytes for null checks
309

    
310
var PRIORITY = 0;
311
var CURRENT_TASK_ID = 1;
312
var CURRENT_RUN_ID = 2;
313
var QUEUE_SIZE = 3;
314

    
315
{
316
  profilingState[PRIORITY] = NoPriority; // This is maintained with a counter, because the size of the priority queue
317
  // array might include canceled tasks.
318

    
319
  profilingState[QUEUE_SIZE] = 0;
320
  profilingState[CURRENT_TASK_ID] = 0;
321
} // Bytes per element is 4
322

    
323

    
324
var INITIAL_EVENT_LOG_SIZE = 131072;
325
var MAX_EVENT_LOG_SIZE = 524288; // Equivalent to 2 megabytes
326

    
327
var eventLogSize = 0;
328
var eventLogBuffer = null;
329
var eventLog = null;
330
var eventLogIndex = 0;
331
var TaskStartEvent = 1;
332
var TaskCompleteEvent = 2;
333
var TaskErrorEvent = 3;
334
var TaskCancelEvent = 4;
335
var TaskRunEvent = 5;
336
var TaskYieldEvent = 6;
337
var SchedulerSuspendEvent = 7;
338
var SchedulerResumeEvent = 8;
339

    
340
function logEvent(entries) {
341
  if (eventLog !== null) {
342
    var offset = eventLogIndex;
343
    eventLogIndex += entries.length;
344

    
345
    if (eventLogIndex + 1 > eventLogSize) {
346
      eventLogSize *= 2;
347

    
348
      if (eventLogSize > MAX_EVENT_LOG_SIZE) {
349
        // Using console['error'] to evade Babel and ESLint
350
        console['error']("Scheduler Profiling: Event log exceeded maximum size. Don't " + 'forget to call `stopLoggingProfilingEvents()`.');
351
        stopLoggingProfilingEvents();
352
        return;
353
      }
354

    
355
      var newEventLog = new Int32Array(eventLogSize * 4);
356
      newEventLog.set(eventLog);
357
      eventLogBuffer = newEventLog.buffer;
358
      eventLog = newEventLog;
359
    }
360

    
361
    eventLog.set(entries, offset);
362
  }
363
}
364

    
365
function startLoggingProfilingEvents() {
366
  eventLogSize = INITIAL_EVENT_LOG_SIZE;
367
  eventLogBuffer = new ArrayBuffer(eventLogSize * 4);
368
  eventLog = new Int32Array(eventLogBuffer);
369
  eventLogIndex = 0;
370
}
371
function stopLoggingProfilingEvents() {
372
  var buffer = eventLogBuffer;
373
  eventLogSize = 0;
374
  eventLogBuffer = null;
375
  eventLog = null;
376
  eventLogIndex = 0;
377
  return buffer;
378
}
379
function markTaskStart(task, ms) {
380
  {
381
    profilingState[QUEUE_SIZE]++;
382

    
383
    if (eventLog !== null) {
384
      // performance.now returns a float, representing milliseconds. When the
385
      // event is logged, it's coerced to an int. Convert to microseconds to
386
      // maintain extra degrees of precision.
387
      logEvent([TaskStartEvent, ms * 1000, task.id, task.priorityLevel]);
388
    }
389
  }
390
}
391
function markTaskCompleted(task, ms) {
392
  {
393
    profilingState[PRIORITY] = NoPriority;
394
    profilingState[CURRENT_TASK_ID] = 0;
395
    profilingState[QUEUE_SIZE]--;
396

    
397
    if (eventLog !== null) {
398
      logEvent([TaskCompleteEvent, ms * 1000, task.id]);
399
    }
400
  }
401
}
402
function markTaskCanceled(task, ms) {
403
  {
404
    profilingState[QUEUE_SIZE]--;
405

    
406
    if (eventLog !== null) {
407
      logEvent([TaskCancelEvent, ms * 1000, task.id]);
408
    }
409
  }
410
}
411
function markTaskErrored(task, ms) {
412
  {
413
    profilingState[PRIORITY] = NoPriority;
414
    profilingState[CURRENT_TASK_ID] = 0;
415
    profilingState[QUEUE_SIZE]--;
416

    
417
    if (eventLog !== null) {
418
      logEvent([TaskErrorEvent, ms * 1000, task.id]);
419
    }
420
  }
421
}
422
function markTaskRun(task, ms) {
423
  {
424
    runIdCounter++;
425
    profilingState[PRIORITY] = task.priorityLevel;
426
    profilingState[CURRENT_TASK_ID] = task.id;
427
    profilingState[CURRENT_RUN_ID] = runIdCounter;
428

    
429
    if (eventLog !== null) {
430
      logEvent([TaskRunEvent, ms * 1000, task.id, runIdCounter]);
431
    }
432
  }
433
}
434
function markTaskYield(task, ms) {
435
  {
436
    profilingState[PRIORITY] = NoPriority;
437
    profilingState[CURRENT_TASK_ID] = 0;
438
    profilingState[CURRENT_RUN_ID] = 0;
439

    
440
    if (eventLog !== null) {
441
      logEvent([TaskYieldEvent, ms * 1000, task.id, runIdCounter]);
442
    }
443
  }
444
}
445
function markSchedulerSuspended(ms) {
446
  {
447
    mainThreadIdCounter++;
448

    
449
    if (eventLog !== null) {
450
      logEvent([SchedulerSuspendEvent, ms * 1000, mainThreadIdCounter]);
451
    }
452
  }
453
}
454
function markSchedulerUnsuspended(ms) {
455
  {
456
    if (eventLog !== null) {
457
      logEvent([SchedulerResumeEvent, ms * 1000, mainThreadIdCounter]);
458
    }
459
  }
460
}
461

    
462
/* eslint-disable no-var */
463
// Math.pow(2, 30) - 1
464
// 0b111111111111111111111111111111
465

    
466
var maxSigned31BitInt = 1073741823; // Times out immediately
467

    
468
var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out
469

    
470
var USER_BLOCKING_PRIORITY = 250;
471
var NORMAL_PRIORITY_TIMEOUT = 5000;
472
var LOW_PRIORITY_TIMEOUT = 10000; // Never times out
473

    
474
var IDLE_PRIORITY = maxSigned31BitInt; // Tasks are stored on a min heap
475

    
476
var taskQueue = [];
477
var timerQueue = []; // Incrementing id counter. Used to maintain insertion order.
478

    
479
var taskIdCounter = 1; // Pausing the scheduler is useful for debugging.
480
var currentTask = null;
481
var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrancy.
482

    
483
var isPerformingWork = false;
484
var isHostCallbackScheduled = false;
485
var isHostTimeoutScheduled = false;
486

    
487
function advanceTimers(currentTime) {
488
  // Check for tasks that are no longer delayed and add them to the queue.
489
  var timer = peek(timerQueue);
490

    
491
  while (timer !== null) {
492
    if (timer.callback === null) {
493
      // Timer was cancelled.
494
      pop(timerQueue);
495
    } else if (timer.startTime <= currentTime) {
496
      // Timer fired. Transfer to the task queue.
497
      pop(timerQueue);
498
      timer.sortIndex = timer.expirationTime;
499
      push(taskQueue, timer);
500

    
501
      {
502
        markTaskStart(timer, currentTime);
503
        timer.isQueued = true;
504
      }
505
    } else {
506
      // Remaining timers are pending.
507
      return;
508
    }
509

    
510
    timer = peek(timerQueue);
511
  }
512
}
513

    
514
function handleTimeout(currentTime) {
515
  isHostTimeoutScheduled = false;
516
  advanceTimers(currentTime);
517

    
518
  if (!isHostCallbackScheduled) {
519
    if (peek(taskQueue) !== null) {
520
      isHostCallbackScheduled = true;
521
      requestHostCallback(flushWork);
522
    } else {
523
      var firstTimer = peek(timerQueue);
524

    
525
      if (firstTimer !== null) {
526
        requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
527
      }
528
    }
529
  }
530
}
531

    
532
function flushWork(hasTimeRemaining, initialTime) {
533
  {
534
    markSchedulerUnsuspended(initialTime);
535
  } // We'll need a host callback the next time work is scheduled.
536

    
537

    
538
  isHostCallbackScheduled = false;
539

    
540
  if (isHostTimeoutScheduled) {
541
    // We scheduled a timeout but it's no longer needed. Cancel it.
542
    isHostTimeoutScheduled = false;
543
    cancelHostTimeout();
544
  }
545

    
546
  isPerformingWork = true;
547
  var previousPriorityLevel = currentPriorityLevel;
548

    
549
  try {
550
    if (enableProfiling) {
551
      try {
552
        return workLoop(hasTimeRemaining, initialTime);
553
      } catch (error) {
554
        if (currentTask !== null) {
555
          var currentTime = exports.unstable_now();
556
          markTaskErrored(currentTask, currentTime);
557
          currentTask.isQueued = false;
558
        }
559

    
560
        throw error;
561
      }
562
    } else {
563
      // No catch in prod codepath.
564
      return workLoop(hasTimeRemaining, initialTime);
565
    }
566
  } finally {
567
    currentTask = null;
568
    currentPriorityLevel = previousPriorityLevel;
569
    isPerformingWork = false;
570

    
571
    {
572
      var _currentTime = exports.unstable_now();
573

    
574
      markSchedulerSuspended(_currentTime);
575
    }
576
  }
577
}
578

    
579
function workLoop(hasTimeRemaining, initialTime) {
580
  var currentTime = initialTime;
581
  advanceTimers(currentTime);
582
  currentTask = peek(taskQueue);
583

    
584
  while (currentTask !== null && !(enableSchedulerDebugging )) {
585
    if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) {
586
      // This currentTask hasn't expired, and we've reached the deadline.
587
      break;
588
    }
589

    
590
    var callback = currentTask.callback;
591

    
592
    if (callback !== null) {
593
      currentTask.callback = null;
594
      currentPriorityLevel = currentTask.priorityLevel;
595
      var didUserCallbackTimeout = currentTask.expirationTime <= currentTime;
596
      markTaskRun(currentTask, currentTime);
597
      var continuationCallback = callback(didUserCallbackTimeout);
598
      currentTime = exports.unstable_now();
599

    
600
      if (typeof continuationCallback === 'function') {
601
        currentTask.callback = continuationCallback;
602
        markTaskYield(currentTask, currentTime);
603
      } else {
604
        {
605
          markTaskCompleted(currentTask, currentTime);
606
          currentTask.isQueued = false;
607
        }
608

    
609
        if (currentTask === peek(taskQueue)) {
610
          pop(taskQueue);
611
        }
612
      }
613

    
614
      advanceTimers(currentTime);
615
    } else {
616
      pop(taskQueue);
617
    }
618

    
619
    currentTask = peek(taskQueue);
620
  } // Return whether there's additional work
621

    
622

    
623
  if (currentTask !== null) {
624
    return true;
625
  } else {
626
    var firstTimer = peek(timerQueue);
627

    
628
    if (firstTimer !== null) {
629
      requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
630
    }
631

    
632
    return false;
633
  }
634
}
635

    
636
function unstable_runWithPriority(priorityLevel, eventHandler) {
637
  switch (priorityLevel) {
638
    case ImmediatePriority:
639
    case UserBlockingPriority:
640
    case NormalPriority:
641
    case LowPriority:
642
    case IdlePriority:
643
      break;
644

    
645
    default:
646
      priorityLevel = NormalPriority;
647
  }
648

    
649
  var previousPriorityLevel = currentPriorityLevel;
650
  currentPriorityLevel = priorityLevel;
651

    
652
  try {
653
    return eventHandler();
654
  } finally {
655
    currentPriorityLevel = previousPriorityLevel;
656
  }
657
}
658

    
659
function unstable_next(eventHandler) {
660
  var priorityLevel;
661

    
662
  switch (currentPriorityLevel) {
663
    case ImmediatePriority:
664
    case UserBlockingPriority:
665
    case NormalPriority:
666
      // Shift down to normal priority
667
      priorityLevel = NormalPriority;
668
      break;
669

    
670
    default:
671
      // Anything lower than normal priority should remain at the current level.
672
      priorityLevel = currentPriorityLevel;
673
      break;
674
  }
675

    
676
  var previousPriorityLevel = currentPriorityLevel;
677
  currentPriorityLevel = priorityLevel;
678

    
679
  try {
680
    return eventHandler();
681
  } finally {
682
    currentPriorityLevel = previousPriorityLevel;
683
  }
684
}
685

    
686
function unstable_wrapCallback(callback) {
687
  var parentPriorityLevel = currentPriorityLevel;
688
  return function () {
689
    // This is a fork of runWithPriority, inlined for performance.
690
    var previousPriorityLevel = currentPriorityLevel;
691
    currentPriorityLevel = parentPriorityLevel;
692

    
693
    try {
694
      return callback.apply(this, arguments);
695
    } finally {
696
      currentPriorityLevel = previousPriorityLevel;
697
    }
698
  };
699
}
700

    
701
function timeoutForPriorityLevel(priorityLevel) {
702
  switch (priorityLevel) {
703
    case ImmediatePriority:
704
      return IMMEDIATE_PRIORITY_TIMEOUT;
705

    
706
    case UserBlockingPriority:
707
      return USER_BLOCKING_PRIORITY;
708

    
709
    case IdlePriority:
710
      return IDLE_PRIORITY;
711

    
712
    case LowPriority:
713
      return LOW_PRIORITY_TIMEOUT;
714

    
715
    case NormalPriority:
716
    default:
717
      return NORMAL_PRIORITY_TIMEOUT;
718
  }
719
}
720

    
721
function unstable_scheduleCallback(priorityLevel, callback, options) {
722
  var currentTime = exports.unstable_now();
723
  var startTime;
724
  var timeout;
725

    
726
  if (typeof options === 'object' && options !== null) {
727
    var delay = options.delay;
728

    
729
    if (typeof delay === 'number' && delay > 0) {
730
      startTime = currentTime + delay;
731
    } else {
732
      startTime = currentTime;
733
    }
734

    
735
    timeout = typeof options.timeout === 'number' ? options.timeout : timeoutForPriorityLevel(priorityLevel);
736
  } else {
737
    timeout = timeoutForPriorityLevel(priorityLevel);
738
    startTime = currentTime;
739
  }
740

    
741
  var expirationTime = startTime + timeout;
742
  var newTask = {
743
    id: taskIdCounter++,
744
    callback: callback,
745
    priorityLevel: priorityLevel,
746
    startTime: startTime,
747
    expirationTime: expirationTime,
748
    sortIndex: -1
749
  };
750

    
751
  {
752
    newTask.isQueued = false;
753
  }
754

    
755
  if (startTime > currentTime) {
756
    // This is a delayed task.
757
    newTask.sortIndex = startTime;
758
    push(timerQueue, newTask);
759

    
760
    if (peek(taskQueue) === null && newTask === peek(timerQueue)) {
761
      // All tasks are delayed, and this is the task with the earliest delay.
762
      if (isHostTimeoutScheduled) {
763
        // Cancel an existing timeout.
764
        cancelHostTimeout();
765
      } else {
766
        isHostTimeoutScheduled = true;
767
      } // Schedule a timeout.
768

    
769

    
770
      requestHostTimeout(handleTimeout, startTime - currentTime);
771
    }
772
  } else {
773
    newTask.sortIndex = expirationTime;
774
    push(taskQueue, newTask);
775

    
776
    {
777
      markTaskStart(newTask, currentTime);
778
      newTask.isQueued = true;
779
    } // Schedule a host callback, if needed. If we're already performing work,
780
    // wait until the next time we yield.
781

    
782

    
783
    if (!isHostCallbackScheduled && !isPerformingWork) {
784
      isHostCallbackScheduled = true;
785
      requestHostCallback(flushWork);
786
    }
787
  }
788

    
789
  return newTask;
790
}
791

    
792
function unstable_pauseExecution() {
793
}
794

    
795
function unstable_continueExecution() {
796

    
797
  if (!isHostCallbackScheduled && !isPerformingWork) {
798
    isHostCallbackScheduled = true;
799
    requestHostCallback(flushWork);
800
  }
801
}
802

    
803
function unstable_getFirstCallbackNode() {
804
  return peek(taskQueue);
805
}
806

    
807
function unstable_cancelCallback(task) {
808
  {
809
    if (task.isQueued) {
810
      var currentTime = exports.unstable_now();
811
      markTaskCanceled(task, currentTime);
812
      task.isQueued = false;
813
    }
814
  } // Null out the callback to indicate the task has been canceled. (Can't
815
  // remove from the queue because you can't remove arbitrary nodes from an
816
  // array based heap, only the first one.)
817

    
818

    
819
  task.callback = null;
820
}
821

    
822
function unstable_getCurrentPriorityLevel() {
823
  return currentPriorityLevel;
824
}
825

    
826
function unstable_shouldYield() {
827
  var currentTime = exports.unstable_now();
828
  advanceTimers(currentTime);
829
  var firstTask = peek(taskQueue);
830
  return firstTask !== currentTask && currentTask !== null && firstTask !== null && firstTask.callback !== null && firstTask.startTime <= currentTime && firstTask.expirationTime < currentTask.expirationTime || shouldYieldToHost();
831
}
832

    
833
var unstable_requestPaint = requestPaint;
834
var unstable_Profiling =  {
835
  startLoggingProfilingEvents: startLoggingProfilingEvents,
836
  stopLoggingProfilingEvents: stopLoggingProfilingEvents,
837
  sharedProfilingBuffer: sharedProfilingBuffer
838
} ;
839

    
840
exports.unstable_IdlePriority = IdlePriority;
841
exports.unstable_ImmediatePriority = ImmediatePriority;
842
exports.unstable_LowPriority = LowPriority;
843
exports.unstable_NormalPriority = NormalPriority;
844
exports.unstable_Profiling = unstable_Profiling;
845
exports.unstable_UserBlockingPriority = UserBlockingPriority;
846
exports.unstable_cancelCallback = unstable_cancelCallback;
847
exports.unstable_continueExecution = unstable_continueExecution;
848
exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel;
849
exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode;
850
exports.unstable_next = unstable_next;
851
exports.unstable_pauseExecution = unstable_pauseExecution;
852
exports.unstable_requestPaint = unstable_requestPaint;
853
exports.unstable_runWithPriority = unstable_runWithPriority;
854
exports.unstable_scheduleCallback = unstable_scheduleCallback;
855
exports.unstable_shouldYield = unstable_shouldYield;
856
exports.unstable_wrapCallback = unstable_wrapCallback;
857
  })();
858
}
(6-6/7)