across
across

Reputation: 157

Convert setInterval to promise

Hello I'm new to javascript and wondering if there is a way to covnert below setInterval thingy into a promise so that .then could be used instead of the callback. Any help?

My ideas:
With a setTimeout I could resolve after a fixed time. But I'm not getting any ideas dealing with setInterval...

function alert_above(scrip, price, callback) {
  var intvl = setInterval(() => {
    if (get_last_price(scrip) > price) {
      callback();
      clearInterval(intvl);
    }
  }, 1000);
 return intvl;
}

Upvotes: 1

Views: 2507

Answers (3)

Wenfang Du
Wenfang Du

Reputation: 11397

Note: poll will be executed without delay the first time, which is different from the native setInterval.

Q: Why is poll based on setTimeout not setInterval?
A: Please see Execute the setInterval function without delay the first time.

Implementation:

// Promisify setTimeout
const pause = (ms, cb, ...args) =>
  new Promise((resolve, reject) => {
    setTimeout(async () => {
      try {
        resolve(await cb?.(...args))
      } catch (error) {
        reject(error)
      }
    }, ms)
  })

// Promisify setInterval
const poll = async (interval, times, cb, ...args) => {
  let result
  const resolve = value => (times = 0) || (result = value)
  const reject = reason => (times = 0) || (result = Promise.reject(reason))
  await (async function basePoll() {
    if (times > 0) {
      const _result = await cb(...args, resolve, reject)
      if (times) {
        result = _result
        --times && (await pause(interval, basePoll))
      }
    }
  })()
  return result
}

Tests:

import ordinal from 'ordinal'

// Test 1
poll(1000, 3, (a, b, c) => [a, b, c], 1, 2, 3).then(value => console.log(value))

// Test 2
let times = 0
poll(1000, 5, resolve => {
  console.log(`${ordinal(++times)} time`)
  times === 3 && resolve('resolved')
}).then(value => console.log(value))

// Test 3
let times = 0
poll(1000, 5, (resolve, reject) => {
  console.log(`${ordinal(++times)} time`)
  times === 3 && reject('rejected')
}).catch(error => console.error(error))

Upvotes: 1

HollyPony
HollyPony

Reputation: 847

I think you could wrap into a new Promise like :

function promisifySetInterval(time) {
  var defer = new Promise(resolve => {
    let counter = 0
    var intvl = setInterval(() => {
      if (counter > time) {
        resolve('hey');
        clearInterval(intvl);
      } else {
        counter += 1000
      }
    }, 1000);
  })
 return defer;
}

promisifySetInterval(2000).then(param => {
  console.log('hey', param)
})

And for youre case something like this :

function alert_above(scrip, price) {
  var defer = new Promise(resolve => {
    var intvl = setInterval(() => {
      if (get_last_price(scrip) > price) {
        resolve('hey');
        clearInterval(intvl);
      }
    }, 1000);
  })
 return defer;
}

alert_above().then(param => {
  console.log('hey', param)
})

Upvotes: 2

Sameer
Sameer

Reputation: 5188

You can create a promise function that resolves asynchronously. Read more about Promise Here

function myInterval() {
  return new Promise(resolve => {
    const intId = setInterval(() => {
      clearInterval(intId);
      resolve();
    }, 1000)
  })
}


myInterval().then(() => {
  console.log('Called after 1 second');
})

Upvotes: 3

Related Questions