Polling with async/await
Tags: javascript, asyncawait, polling
Published: 2019-09-19 07:28:50

---
title: Polling with async/await
published: true
description: 
tags: javascript, asyncawait, polling
---

This article is based on my real experience with refactoring a small piece of code with polling function so I won’t be starting from the scratch. I know its not rocket science, but I was looking for the solution for polling in the past and I found similar articles very helpful. It’s also a nice demonstration of how `async/await` and higher-order functions could help to code maintainability and readability.

I have been using the following piece of code for some polling functionality for a while.

```js
function originalPoll(fn, end) {
  async function checkCondition() {
    const result = await fn();
    console.log("result", result);
    if (result < 3) {
      setTimeout(checkCondition, 3000);
    } else {
      end();
    }
  }

  checkCondition();
}
```

It takes function `fn` and calls it every 3 seconds until it gets required result (I simplified it here to a condition `result < 3`), then it calls callback `end` passed as the second parameter. The function somehow works and does what I need. But, it’s not possible to re-use it with a different condition. So I decided to refactor it a little bit. After a few minutes of thinking and tweaking I finally ended up with this simplification:

```js
async function poll(fn, fnCondition, ms) {
  let result = await fn();
  while (fnCondition(result)) {
    await wait(ms);
    result = await fn();
  }
  return result;
}

function wait(ms = 1000) {
  return new Promise(resolve => {
    console.log(`waiting ${ms} ms...`);
    setTimeout(resolve, ms);
  });
}
```

This function still calls the `fn` function repeatedly, but now it takes also another parameter `fnCondition` which is called with the result of calling the `fn` function. Function `poll` will be calling the function `fn` until the function `fnCondition` returns `false`. I also extracted `setTimeout` function, it improves the readability of the polling function and keeps its responsibility straightforward (I don’t care how the waiting is implemented at this abstraction level). We also got rid of function inside a function which just added unnecessary complexity.

I didn’t start with a test first to be honest. Anyway, I still wanted to check my design, provide some safety for the future refactoring and also to document how to call the `poll` function. We can nicely achieve all of that by adding some tests:

```js
describe("poll", () => {
  it("returns result of the last call", async () => {
    const fn = createApiStub();
    const fnCondition = result => result < 3;
    const finalResult = await poll(fn, fnCondition, 1000);
    expect(finalResult).toEqual(3);
  });

  it("calls api many times while condition is satisfied", async () => {
    const fn = createApiStub();
    const fnCondition = result => result < 3;
    await poll(fn, fnCondition, 1000);
    expect(fn).toHaveBeenCalledTimes(3);
  });

  function createApiStub() {
    let counter = 0;
    const testApi = () => {
      console.log("calling api", counter);
      counter++;
      return counter;
    };
    return jest.fn(() => testApi());
  }
});
```

I’m using Jest as a testing library. It has great support for testing async functions and provides stubs with assertions by default. Function `createApiStub` is here just for the purpose of the test and assertions and it'll represent our real API call or whatever function we would want to poll.

You can find and run the code in this CodeSandbox: [Polling with async/await - CodeSandbox](https://codesandbox.io/s/ovqop57mzy).