/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
2604150425000
src/service/timer-impl.js
189 строк
5 KB
Ryan Cebulko
♻️ Move files into #core, #utils to enable tsc typechecking (#36277)
07 окт 2021, 23:26
Не верифицирован
07 окт 2021, 23:26
b6d1550
Код
Авторство
О чём код?
import {user} from '#utils/log'; import {reportError} from '../error-reporting'; import {getMode} from '../mode'; import { registerServiceBuilder, registerServiceBuilderInEmbedWin, } from '../service-helpers'; const TAG = 'timer'; let timersForTesting; /** * Helper with all things Timer. */ export class Timer { /** * @param {!Window} win */ constructor(win) { /** @const {!Window} */ this.win = win; /** @private @const {!Promise} */ this.resolved_ = this.win.Promise.resolve(); this.taskCount_ = 0; this.canceled_ = {}; /** @const {number} */ this.startTime_ = Date.now(); } /** * Returns time since start in milliseconds. * @return {number} */ timeSinceStart() { return Date.now() - this.startTime_; } /** * Runs the provided callback after the specified delay. This uses a micro * task for 0 or no specified time. This means that the delay will actually * be close to 0 and this will NOT yield to the event queue. * * Returns the timer ID that can be used to cancel the timer (cancel method). * @param {function()} callback * @param {number=} opt_delay * @return {number|string} */ delay(callback, opt_delay) { if (!opt_delay) { // For a delay of zero, schedule a promise based micro task since // they are predictably fast. const id = 'p' + this.taskCount_++; this.resolved_ .then(() => { if (this.canceled_[id]) { delete this.canceled_[id]; return; } callback(); }) .catch(reportError); return id; } const wrapped = () => { try { callback(); } catch (e) { reportError(e); throw e; } }; const index = this.win.setTimeout(wrapped, opt_delay); if (getMode().test) { if (!timersForTesting) { timersForTesting = []; } timersForTesting.push(index); } return index; } /** * Cancels the previously scheduled callback. * @param {number|string|null} timeoutId */ cancel(timeoutId) { if (typeof timeoutId == 'string') { this.canceled_[timeoutId] = true; return; } this.win.clearTimeout(timeoutId); } /** * Returns a promise that will resolve after the delay. Optionally, the * resolved value can be provided as opt_result argument. * @param {number=} opt_delay * @return {!Promise} */ promise(opt_delay) { return new this.win.Promise((resolve) => { // Avoid wrapping in closure if no specific result is produced. const timerKey = this.delay(resolve, opt_delay); if (timerKey == -1) { throw new Error('Failed to schedule timer.'); } }); } /** * Returns a promise that will fail after the specified delay. Optionally, * this method can take opt_racePromise parameter. In this case, the * resulting promise will either fail when the specified delay expires or * will resolve based on the opt_racePromise, whichever happens first. * @param {number} delay * @param {?Promise<RESULT>|undefined} opt_racePromise * @param {string=} opt_message * @return {!Promise<RESULT>} * @template RESULT */ timeoutPromise(delay, opt_racePromise, opt_message) { let timerKey; const delayPromise = new this.win.Promise((_resolve, reject) => { timerKey = this.delay(() => { reject(user().createError(opt_message || 'timeout')); }, delay); if (timerKey == -1) { throw new Error('Failed to schedule timer.'); } }); if (!opt_racePromise) { return delayPromise; } const cancel = () => { this.cancel(timerKey); }; opt_racePromise.then(cancel, cancel); return this.win.Promise.race([delayPromise, opt_racePromise]); } /** * Returns a promise that resolves after `predicate` returns true. * Polls with interval `delay` * @param {number} delay * @param {function():boolean} predicate * @return {!Promise} */ poll(delay, predicate) { return new this.win.Promise((resolve) => { const interval = this.win.setInterval(() => { if (predicate()) { this.win.clearInterval(interval); resolve(); } }, delay); }); } } /** * @param {!Window} window */ export function installTimerService(window) { registerServiceBuilder(window, TAG, Timer); } /** * @param {!Window} embedWin */ export function installTimerInEmbedWindow(embedWin) { registerServiceBuilderInEmbedWin(embedWin, TAG, Timer); } /** * Cancels all timers scheduled during the current test */ export function cancelTimersForTesting() { if (!timersForTesting) { return; } timersForTesting.forEach(clearTimeout); timersForTesting = null; }