Как вернуть обещание с помощью setInterval()

#javascript #promise #setinterval

#javascript #обещание #setinterval

Вопрос:

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

РЕДАКТИРОВАТЬ Похоже, я не очень четко представлял свои намерения, поэтому я попытаюсь объяснить, что я пытаюсь сделать. Я делаю обратный отсчет, когда необходимые вычисления выполняются каждые 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);
  

Комментарии:

1. Обещание решается только один раз, поэтому неясно, чего вы хотите достичь

2. Я думаю, что то, что вы ищете, — это асинхронный итерируемый

3. вы не должны возвращаться и просто запускать свое обещание внутри setInterval

4. setInterval возвращает ссылку на интервал, она не возвращает возврат обратного вызова. Кроме того, обещание может быть разрешено только один раз. Чего вы пытаетесь достичь?

5. Вы можете только return один раз, а не » каждые 1000 мс »

Ответ №1:

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

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

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

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

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

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

 class Observable {
    constructor(exec) {
        this.listeners = new Set;
        exec({
            next: (value) => this.listeners.forEach(({next}) => next amp;amp; next(value)),
            error: (err) => this.listeners.forEach(({error}) => error amp;amp; error(err)),
            complete: () => this.listeners.forEach(({complete}) => complete amp;amp; 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 .

Комментарии:

1. как я мог остановить цикл без использования события click? в пределах разрешения или отклонения интервала.subscribe? интервал.subscribe ({next: (data) => this . APISaleID (данные) .затем (ответ =>{ интервал.subscribe.unsubscribe = true // остановитесь тогда здесь })})

2. Если у вас есть новый вопрос, пожалуйста, используйте кнопку Задать вопрос.

3. это не новый вопрос, а вопрос о том же

4. В этом вопросе нет события щелчка, и OP ничего не спрашивал об остановке цикла. Это было просто необязательное дополнение, которое я добавил, чего мне, вероятно, не следовало делать. Итак, да, вы задаете новый вопрос. Комментарии предназначены для разъяснений, исправлений, замечаний, … а не для новых вопросов или даже последующих вопросов.

Ответ №2:

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

Разница в том, что асинхронная итерация будет генерировать следующее обещание только в том случае, если вы используете последнее. Интервалы в 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)
  

Комментарии:

1. Я обновил свой вопрос, надеюсь, это имеет немного больше смысла

Ответ №3:

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

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

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

способ 1:

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

способ 2:

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

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

 setTimeout(() => {
  clearInterval(intervalId);
}, 10000);
  

Комментарии:

1. Извините, но const intervalId = setInterval(() => { interval().then((x) => { console.log(x); единственный возврат один раз, мне придется придумать другой метод

Ответ №4:

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

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

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

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

дескриптор = окно . setInterval( обработчик [, тайм-аут [, аргументы ] ] )

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)
  

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

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

 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;
        }
  

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

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

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

Ответ №5:

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

 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);  

Комментарии:

1. Обновил мой вопрос

2. после стольких комментариев в вашем обновленном вопросе снова говорится i would like returned as a Promise value every 1000ms: , что вы не можете, как и где вы пытаетесь использовать эти обещания? @FrederickM.Rogers

Ответ №6:

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, возможно, он будет соответствовать вашим потребностям