1

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;
}
Wenfang Du
  • 8,804
  • 9
  • 59
  • 90
across
  • 157
  • 7
  • 1
    Does this answer your question? [How to return a Promise with setInterval()](https://stackoverflow.com/questions/55759643/how-to-return-a-promise-with-setinterval) – Nir Alfasi May 20 '20 at 08:40
  • @alfasin that question seems to be about returning a promise every 1000ms. My question requires returning just one promise in the end... Thanks though:) – across May 20 '20 at 08:43
  • 4
    @beccaboo Conceptually, what you're asking for doesn't work. An interval ticks multiple times, but a promise can only be resolved once. – Etheryte May 20 '20 at 08:46

3 Answers3

2

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)
})
HollyPony
  • 817
  • 9
  • 15
2

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');
})
Sameer
  • 4,758
  • 3
  • 20
  • 41
1

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))
Wenfang Du
  • 8,804
  • 9
  • 59
  • 90