如何使用setInterval()

时间:2019-04-19 09:31:23

标签: javascript promise setinterval

我试图每1000ms返回一个Promise对象,但是当它在setInterval()回调中时,我不确定如何访问Promise中返回的数据。

编辑 我似乎对自己的意图不是很清楚,所以我将尽力解释我要做什么。我记下了根据指定的结束日期每1000毫秒进行一次必要计算的数字。

以下是提供返回值的代码,我希望每1000毫秒以Pormise值返回该返回值:

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

此后如何使用.then()访问Promise对象?

不起作用:

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

6 个答案:

答案 0 :(得分:1)

您正在寻找的是可观察的,而不是承诺。使用promise,传递给then的回调最多执行一次,因此:

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

...即使您更正了代码中的以下错误,也绝不会多次打印“ Hello”:

  • 您在return回调函数中setInterval进行的操作都会被忽略。
  • setInterval不返回Promise,而是一个整数,唯一标识创建的间隔计时器。

另一方面,与Promise相反,一个Observable 可以发出多个事件。

EcmaScript有一个Observable proposal,但您可以创建自己的版本-非常简化-

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

答案 1 :(得分:0)

根据您实际要执行的操作,异步可迭代对象可能会完成这项工作。

区别在于异步可迭代项仅在消耗了最后一个承诺后才会生成下一个承诺。即使没有承诺,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)

答案 2 :(得分:0)

正如评论中已经提到的那样,您不能定期返回承诺,但是可以将它们保留在全局对象中,以后再使用,

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

答案 3 :(得分:0)

对于时间间隔,您可以像这样定义时间间隔函数

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

答案 4 :(得分:0)

我不确定这是否有帮助,但是;任何功能都可以实现,在这种情况下,替代语法[async关键字]可能对您有用。

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

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

setInterval()不会返回返回值,而是返回一个“句柄”。

handle = window。 setInterval(handler [,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。

更好地使您的calculateTimeRemaining到一个承诺然后您可以在间隔上使用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;
        }

但是,promise的价值在于避免使用过于复杂的回调方案来进行回调……代码在其中进行回调,从回调,从回调等等等。

承诺不会像Webworker那样在第二个操作系统线程中运行。因此,除非您试图清理回调以使代码可读或实际上正在等待某些事情,否则使用诺言是没有好处的。

setInterval是一个干净的回调。 Gameloop示例不容易阅读和理解,因为使用了Promise。我建议在这种情况下更难阅读。在这一点上...除非循环中有其他等待或一系列不需要同步运行的promise;

答案 5 :(得分:-2)

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,也许它可以满足您的需求