Как вернуть Обещание с помощью setInterval () - PullRequest
0 голосов
/ 19 апреля 2019

Я пытаюсь вернуть объект Promise когда-либо 1000 мс, но я не уверен, как получить доступ к данным, возвращенным в Promise, когда он находится внутри обратного вызова setInterval().

EDIT Похоже, я не очень ясно понял свои намерения, поэтому я попытаюсь объяснить, что я пытаюсь сделать.Я сделал обратный отсчет, где с помощью необходимых вычислений выполняются каждые 1000 мс на основе указанной даты окончания.

Вот код, который предоставляет возвращаемое значение, которое я хотел бы возвращать как значение Pormise каждые 1000 мс:

calculateTimeRemaining(endDate: string) {
            const { secondsInDay, daysOfYear, secondsInHour, secondsInMinute } = this.unitsOfTime;
            let distance: number =
                (Date.parse(new Date(endDate).toString()) - Date.parse(new Date().toString())) / this.increment;

            if (distance > 0) {
                // Years left
                if (distance >= daysOfYear * secondsInDay) {
                    // 365.25 * 24 * 60 * 60
                    this.timeRemaining.years = Math.floor(distance / (daysOfYear * secondsInDay));
                    distance -= this.timeRemaining.years * daysOfYear * secondsInDay;
                }
                // Days left
                if (distance >= secondsInDay) {
                    // 24 * 60 * 60
                    this.timeRemaining.days = Math.floor(distance / secondsInDay);
                    distance -= this.timeRemaining.days * secondsInDay;
                }
                // Hours left
                if (distance >= secondsInHour) {
                    // 60 * 60
                    this.timeRemaining.hours = Math.floor(distance / secondsInHour);
                    distance -= this.timeRemaining.hours * secondsInHour;
                }
                // Minutes left
                if (distance >= secondsInMinute) {
                    // 60
                    this.timeRemaining.minutes = Math.floor(distance / secondsInMinute);
                    distance -= this.timeRemaining.minutes * secondsInMinute;
                }
                // Seconds left
                this.timeRemaining.seconds = distance;
            }
            return this.timeRemaining;
        }

Пример:

    const interval = window.setInterval(() => {
        return new Promise((resolve, reject) => {
            resolve('Hello');
        });
    }, 1000);

Как получить доступ к объекту Promise после .then()?

Не работает:

interval.then((data) => console.log(data);

Ответы [ 6 ]

2 голосов
/ 19 апреля 2019

То, что вы ищете, это Observable, а не Promise. С обещаниями, обратный вызов, который вы передаете then, выполняется не более одного раза, так что:

interval.then((data) => console.log(data));

... никогда не будет печатать «Hello» более одного раза, даже если вы исправили следующие ошибки в своем коде:

  • Все, что вы return в функции обратного вызова setInterval игнорируется.
  • setInterval возвращает не обещание, а целое число, однозначно определяющее созданный интервальный таймер.

С другой стороны, Наблюдаемая может испускать несколько событий вопреки Обещанию.

Существует Наблюдаемое предложение для EcmaScript, но вы можете создать свою собственную - очень упрощенную - его версию:

class Observable {
    constructor(exec) {
        this.listeners = new Set;
        exec({
            next: (value) => this.listeners.forEach(({next}) => next && next(value)),
            error: (err) => this.listeners.forEach(({error}) => error && error(err)),
            complete: () => this.listeners.forEach(({complete}) => complete && complete())
        });
    }
    subscribe(listeners) {
        this.listeners.add(listeners);
        return { unsubscribe: () => this.listeners.delete(listeners) }
    }
}

// Create an Observable instead of a Promise;
const interval = new Observable(({next}) => {
    setInterval(() => next("Hello"), 1000);
});

// Subscribe to that Observable
const subscription = interval.subscribe({ next: (data) => console.log(data) });

// Optionally use the returned subscription object to stop listening:
document.querySelector("button").addEventListener("click", subscription.unsubscribe);
<button>Stop listening</button>

Обратите внимание, что несколько JavaScript-фреймворков имеют реализацию Observable.

0 голосов
/ 19 апреля 2019

Я не уверен, поможет ли это, но; Любую функцию можно превратить в обещание, и в этом случае вам может пригодиться альтернативный синтаксис [ключевое слово async].

async function test() {
      return "hello";
}

test().then( returned => console.log(returned)) // logs hello

setInterval (), однако, не возвращает возвращаемого значения, а возвращает «дескриптор».

ручка = окно. setInterval (обработчик [, timeout [, arguments]])

... https://www.w3.org/TR/2011/WD-html5-author-20110705/spec.html#timers

Однако вы можете давать обещания из setinterval ...

interval = window.setInterval(makepromise,1000)
async function makepromise() {
    console.log("hello");
}

// или

interval = window.setInterval(async function () {console.log("hello");},1000)

Но тогда нет места для. Мы вернулись к обратным вызовам, которых мы пытались избежать! Но, возможно, есть функциональность, которую мы можем использовать await в этой функции.

Лучше сделать ваш calcTime оставшимся к обещанию, а затем вы можете использовать затем на интервале.

interval = window.setInterval(gameloop,1000);

    function gameloop(endDate: string) {
        calculateTimeRemaining(endDate: string).then(
//
// my then code goes here.
//
        )
    }

async calculateTimeRemaining(endDate: string) {
            const { secondsInDay, daysOfYear, secondsInHour, secondsInMinute } = this.unitsOfTime;
            let distance: number =
                (Date.parse(new Date(endDate).toString()) - Date.parse(new Date().toString())) / this.increment;

            if (distance > 0) {
                // Years left
                if (distance >= daysOfYear * secondsInDay) {
                    // 365.25 * 24 * 60 * 60
                    this.timeRemaining.years = Math.floor(distance / (daysOfYear * secondsInDay));
                    distance -= this.timeRemaining.years * daysOfYear * secondsInDay;
                }
                // Days left
                if (distance >= secondsInDay) {
                    // 24 * 60 * 60
                    this.timeRemaining.days = Math.floor(distance / secondsInDay);
                    distance -= this.timeRemaining.days * secondsInDay;
                }
                // Hours left
                if (distance >= secondsInHour) {
                    // 60 * 60
                    this.timeRemaining.hours = Math.floor(distance / secondsInHour);
                    distance -= this.timeRemaining.hours * secondsInHour;
                }
                // Minutes left
                if (distance >= secondsInMinute) {
                    // 60
                    this.timeRemaining.minutes = Math.floor(distance / secondsInMinute);
                    distance -= this.timeRemaining.minutes * secondsInMinute;
                }
                // Seconds left
                this.timeRemaining.seconds = distance;
            }
            return this.timeRemaining;
        }

Однако значение обещаний состоит в том, чтобы избежать ада обратного вызова с чрезмерно сложной схемой обратного вызова ... когда код выполняет обратный вызов, от обратных вызовов, от обратных вызовов и т. Д., И т. Д. И т. Д.

Обещания не работают во втором потоке операционной системы, как веб-работник. Поэтому, если вы не пытаетесь очистить обратные вызовы, чтобы сделать код читабельным, или на самом деле ждете чего-то, бесполезно использовать обещания.

setInterval - это чистый обратный вызов. Пример Gameloop не легче прочитать и понять, потому что было использовано обещание. Я бы предположил, что в этом случае его сложнее читать. на этом этапе ... если в цикле нет других ожидающих или серии обещаний, которые не должны выполняться синхронно;

0 голосов
/ 19 апреля 2019

Для интервала вы можете определить функцию интервала следующим образом:

 function interval() {
    return new Promise(function(resolve, reject) {
        setInterval(function() {                 
           resolve('Hello');
        }, 1000)
  })
};

Для интервала вы можете использовать это:

way 1:

interval().then((x) => {
   console.log(x);

})

путь 2:

const intervalId = setInterval(() => {
   interval().then((x) => {
   console.log(x);

}, 1000)})

Это просто для остановки функции интервала через некоторое время.Вы должны очистить интервал, если он вам больше не нужен.

setTimeout(() => {
    clearInterval(intervalId);
}, 10000);
0 голосов
/ 19 апреля 2019

Как уже упоминалось в комментариях, вы не можете возвращать обещания через интервалы, но вы можете хранить их в глобальном объекте и использовать позже,

const jobs = []
const interval = setInterval(() => {
	if(jobs.length == 10) {
		clearInterval(interval);
	}
	let job = Promise.resolve('new job created');
	jobs.push(job);
	console.log('job created')
}, 1000);

setTimeout(() => {
	Promise.all(jobs).then(data => console.log(data))
}, 1000*15);
0 голосов
/ 19 апреля 2019

В зависимости от того, что вы на самом деле пытаетесь сделать, асинхронная итерация может выполнять эту работу.

Разница в том, что асинхронная итерация генерирует только следующее обещание, если вы используете последнее.Интервалы в JavaScript сложны даже без обещаний.Они пытаются запускать обратный вызов через равные промежутки времени, но выполнение любого обратного вызова может быть отложено, если интерпретатор занят.Эта задержка не будет распространяться, однако.Кроме того, короткие интервалы будут регулироваться для фоновых вкладок.

Если ваш код всегда ожидает асинхронного повторения (например, в цикле for…of), вы можете сделать это:

function delay(t) {
  return new Promise(resolve => setTimeout(resolve, t))
}

async function *interval(t) {
  while(true) {
    let now = Date.now()
    yield "hello"
    await delay(now - Date.now() + t)
  }
}

for await(const greeting of interval(1000)) console.log(greeting)
0 голосов
/ 19 апреля 2019

setInterval уже возвращает целое число, которое полезно для отмены этого интервала, используя clearInterval.

const promise = new Promise((resolve, reject) => {
        resolve('Hello');
    });

Тогда используйте это как


promise.then((result) => {
 console.log(result) // Says 'Hello' and will not resolve another value if we call it as it has already been resolved
})

Может быть, это то, что вы пытались достичь. Если вы хотите позвонить с интервалом 1000 мс.

const getPromiseInstance = () => new Promise((resolve, reject) => {
        resolve(Math.random());
    });

setInterval(() => {
    getPromiseInstance().then((result) => {
      console.log(result)
    })
}, 1000)

Вы должны взглянуть на Observable, возможно, он будет соответствовать вашим потребностям

...