Promise – JavaScript challenges

You can find all the code in this post at the repo Github.

Async programming Promise related challenges

Add two promises

/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/

async fun…


This content originally appeared on DEV Community and was authored by Mitchell

You can find all the code in this post at the repo Github.

Async programming Promise related challenges

Add two promises

/**
 * @param {Promise} promise1 
 * @param {Promise} promise2 
 * @return {Promise}
 */

async function addTwoPromises(promise1, promise2) {
  return new Promise(async (resolve) => {
    const result1 = await promise1;
    const result2 = await promise2;

    return resolve(result1 + result2);
  });
}

// Usage example
addTwoPromises(
  Promise.resolve(2), Promise.resolve(2)
)
.then(console.log); // => 4

Async addition

function asyncAdd(a, b, callbackFn) {
  setTimeout(() => {
    callbackFn(null, a + b);
  }, Math.random() * 1000);
}

async function sum(...args) {
  let total = 0;

  // helper
  const add = (a, b) => {
    return new Promise((resolve) => {
      asyncAdd(a, b, (err, result) => {
        if (err) {
          throw err;
        }
        resolve(result);
      });
    });
  };

  for (const arg of args) {
    total = await add(total, arg);
  }

  return total;
}

// Usage example
async function total() {
  const res1 = await sum(1, 2, 3, 4, 5, 6, 4);
  const res2 = await sum(1, 2, 3, 4, 5, 6, 4);
  return [res1, res2];
}

total().then((result) => console.log(result));

Auto retry promise on rejection

/**
 * @param {() => Promise<any>} fetcher
 * @param {number} maximumRetryCount
 * @return {Promise<any>}
 */

// Recursive approach
function fetchWithAutoRetry(fetcher, maximumRetryCount = 5) {
  return fetcher()
    .catch((err) => {
      if (maximumRetryCount === 0) {
        throw err;
      } else {
        return fetchWithAutoRetry(fetcher, maximumRetryCount - 1);
      }
    });
}

// Iterative approach
function fetchWithAutoRetry(fetcher, maximumRetryCount = 5) {
  return new Promise((resolve, reject) => {
    function attempt(count) {
      fetcher()
        .then(resolve)
        .catch((err) => {
          if (count === 0) {
            reject(err);
          } else {
            attempt(count - 1);
          }
        });
    }

    attempt(maximumRetryCount);
  });
}

// Usage example
function simulateAPICall() {
  return new Promise((resolve, reject) => {
    // Simulate a 50% chance of failure
    if (Math.random() < 0.5) {
      reject(new Error('API call failed'));
    } else {
      resolve('API call succeeded');
    }
  });
}

fetchWithAutoRetry(simulateAPICall, 3)
  .then(result => {
    console.log('Success:', result);
  })
  .catch(error => {
    console.error('All retries failed:', error.message);
  });

// Example output (may vary due to randomness):
// Success: API call succeeded

// Or if all retries fail:
// All retries failed: API call failed

Call APIs with pagination

// const fetchList = (since?: number) => 
//   Promise<{items: Array<{id: number}>}>

const fetchListWithAmount = async (amount = 5) => {
  const result = [];

  function request(id) {
    return fetchList(id).then(({ items }) => {
      result.push(...items);

      if (result.length >= amount || !items.length) {
        return result.slice(0, amount);
      }

      const { id: lastItemId } = result.at(-1);

      return request(lastItemId);
    });
  } 

  return request();
}

Cancel request

const URL = 'https://jsonplaceholder.typicode.com/posts/1';
const TIMEOUT = 5000;

function fetchDataWithTimeout(url, timeout) {
  const controller = new AbortController();
  const { signal } = controller;

  const timerId = setTimeout(() => {
    controller.abort();
  }, timeout);

  return fetch(url, { signal })
    .then((response) => {
      clearTimeout(timerId);

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return response.json();
    })
    .catch((err) => {
      if (err.name === 'AbortError') {
        throw new Error('Fetch operation timed out');
      } else {
        throw err;
      }
    });
}

// Usage example
fetchDataWithTimeout(URL, TIMEOUT)
  .then(data => {
    console.log('Fetched data:', data);
    console.log('Title:', data.title);
    console.log('Body:', data.body);
  })
  .catch(error => {
    console.error('Error:', error.message);
  });

/*
Fetched data: {
  userId: 1,
  id: 1,
  title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
  body: 'quia et suscipit\n' +
    'suscipit recusandae consequuntur expedita et cum\n' +
    'reprehenderit molestiae ut ut quas totam\n' +
    'nostrum rerum est autem sunt rem eveniet architecto'
}
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto
*/

// Or

// Error: Request timed out || Error: [Specific error message]

Concurrent data fetching

const URL_ARR = [
  'https://fastly.picsum.photos/id/0/5000/3333.jpg?hmac=_j6ghY5fCfSD6tvtcV74zXivkJSPIfR9B8w34XeQmvU',
  'https://fastly.picsum.photos/id/1/5000/3333.jpg?hmac=Asv2DU3rA_5D1xSe22xZK47WEAN0wjWeFOhzd13ujW4',
  'https://fastly.picsum.photos/id/2/5000/3333.jpg?hmac=_KDkqQVttXw_nM-RyJfLImIbafFrqLsuGO5YuHqD-qQ',
  'https://fastly.picsum.photos/id/3/5000/3333.jpg?hmac=GDjZ2uNWE3V59PkdDaOzTOuV3tPWWxJSf4fNcxu4S2g'
];

function fetchData(url) {
  return fetch(url)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error: ${response.statu}`);
      }

      return response.blob();
    });
}

Promise.all(URL_ARR.map(fetchData))
  .then((results) => {
    console.log(results);
  })
  .catch((err) => {
    console.log(err);
  });

/*
  [
    Blob { size: 490823, type: 'image/jpeg' },
    Blob { size: 417790, type: 'image/jpeg' },
    Blob { size: 451977, type: 'image/jpeg' },
    Blob { size: 395440, type: 'image/jpeg' }
  ]
*/

LazyMan

class LazyMan {
  constructor(name) {
    this.name = name;
    console.log(`My name is ${name}`);
    this.taskQueue = [];

    setTimeout(() => {
      return this.next();
    }, 0);
  }

  eat(food) {
    this.taskQueue.push(() => {
      console.log(`I am eating ${food}`);
      this.next();
    });

    return this;
  }

  sleep(delay) {
    this.taskQueue.push(() => {
      console.log('I am sleeping...');
      setTimeout(() => {
        console.log(`After ${delay} seconds`);
        this.next();
      }, delay);
    });

    return this;
  }

  next() {
    const fn = this.taskQueue.shift();
    if (typeof fn === 'function') {
      fn();
    }
  }
}

// Usage example
const lazyMan = new LazyMan('jack');
lazyMan.eat('apple').sleep(5000).eat('hamburger').sleep(3000).eat('pear');

/*
My name is jack
I am eating apple
I am sleeping...
After 5000 seconds
I am eating hamburger
I am sleeping...
After 3000 seconds
I am eating pear
*/

Load images concurrently

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();

    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error(`Could not load image at ${url}`));

    img.src = url;
  });
}

function loadImages(urls) {
  const promises = urls.map(url => loadImage(url));

  return Promise.all(promises)
    .then(images => {
      images.forEach(img => document.body.appendChild(img));
      console.log('All images loaded successfully!');
    })
    .catch(err => {
      console.error(err);
    });
}

// Usage example
const imageUrls = [
  'https://picsum.photos/200/300',
  'https://picsum.photos/200/300?random=1',
  'https://picsum.photos/200/300?random=2',
  'https://picsum.photos/200/300?random=3',
  'https://picsum.photos/200/300?random=4'
];

loadImages(imageUrls);

Log promise

function sleep(delay) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, delay);
  });
};


// promise based
function logNumbers() {
  let promise = Promise.resolve();

  for (let i = 1; i <= 5; i += 1) {
    promise = promise.then(() => {
      console.log(i);
      return sleep(1000);
    });
  }

  return promise;
}

// async-await based
async function logNumbers() {
  for (let i = 1; i <= 5; i += 1) {
    console.log(i);
    await sleep(1000);
  }
}

// Usage example
logNumbers()
  .then(() => {
    console.log('finished!'); // => 'finished!'
  });

Make a request

const URL = 'https://randomuser.me/api/';

/**
 * @param {string} url
 * @return {promise}
 */

// promise-based
function fetchData(url) {
  return fetch(url)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`Error: ${response.status}`);
      }

      return response.json();
    })
    .catch((err) => {
      console.error('Fetch error:', err);
      throw err;
    });
}

// async-await based
async function fetchData(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error(`Error: ${response.status} - ${response.statusText}`);
    }

    return await response.json();
  } catch (err) {
    console.error(`Request error: ${err}`);
    throw err;
  }
}

fetchData(URL)
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.log(`Request error: ${err}`);
  });
/*
{
  results: [
    {
      gender: 'male',
      name: [Object],
      location: [Object],
      email: 'joanikije.lazic@example.com',
      login: [Object],
      dob: [Object],
      registered: [Object],
      phone: '034-5670-262',
      cell: '067-5723-987',
      id: [Object],
      picture: [Object],
      nat: 'RS'
    }
  ],
  info: { seed: '38e4419ddfa3cd4d', results: 1, page: 1, version: '1.4' }
}
*/

Map async

/**
 * @params {Array} iterable
 * @params {callbackFn} Function
 * @return {Array}
 */

// Use Promise.all()
function mapAsync(iterable, callbackFn) {
  return Promise.all(iterable.map(callbackFn));
}

// Iterative
function mapAsync(iterable, callbackFn) {
  return new Promise((resolve, reject) => {
    const results = [];
    let unresolved = iterable.length;

    if (!unresolved) {
      resolve(results);
      return;
    }

    iterable.forEach((item, index) => {
      callbackFn(item)
        .then((result) => {
          results[index] = result;
          unresolved -= 1;

          if (!unresolved) {
            resolve(results);
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  });
}

// Usage example
function asyncDouble(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x * 2);
    }, 1000);
  });
}

mapAsync([1, 2], asyncDouble)
  .then((results) => {
    console.log(results); // => [2, 4]
  });

Map async limit

/**
 * @param {Array<any>} iterable
 * @param {Function} callbackFn
 * @param {number} size
 * @return {Promise}
 */

// Chunk approach
async function mapAsyncLimit(iterable, callbackFn, size = Infinity) {
  const results = [];

  for (let i = 0; i < iterable.length; i += size) {
    const chunk = iterable.slice(i, i + size);
    const chunkResults = await Promise.all(chunk.map(callbackFn));

    results.push(...chunkResults);
  }

  return results;
}

// Chunkless approach
function mapAsyncLimit(iterable, callbackFn, size = Infinity) {
  return new Promise((resolve, reject) => {
    const results = [];
    let resolved = 0;
    let nextIndex = 0;
    let len = iterable.length;

    if (!len) {
      resolve(results);
      return;
    }

    async function processItem(index) {
      nextIndex += 1;

      try {
        const result = await callbackFn(iterable[index]);
        results[index] = result;
        resolved += 1;

        if (resolved === len) {
          resolve(results);
          return;
        }

        if (nextIndex < len) {
          processItem(nextIndex);
        }
      } catch (err) {
        reject(err);
      }
    }

    for (let i = 0; i < Math.min(len, size); i += 1) {
      processItem(i);
    }
  });
}

// Promise-based
function mapAsyncLimit(iterable, callbackFn, size = Infinity) {
  return new Promise((resolve, reject) => {
    const results = [];
    let resolved = 0;
    let nextIndex = 0;
    let len = iterable.length;

    if (!len) {
      resolve(results);
      return;
    }

    function processItem(index) {
      nextIndex += 1;

      callbackFn(iterable[index])
        .then((result) => {
          results[index] = result;
          resolved += 1;

          if (resolved === len) {
            resolve(results);
            return;
          }

          if (nextIndex < len) {
            processItem(nextIndex);
          }
        }).catch(reject);
    }

    for (let i = 0; i < Math.min(len, size); i += 1) {
      processItem(i);
    }
  });
}

// Usage example
function asyncSquare(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`Processing ${x}`);
      resolve(x * x);
    }, Math.random() * 1000);
  });
}

// Usage example
async function runExample() {
  const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const chunkSize = 3;

  console.log("Starting async processing...");

  const results = await mapAsyncLimit(numbers, asyncSquare, chunkSize);

  console.log("All processing complete.");
  console.log("Results:", results);
}

runExample();

/*
Starting async processing...
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
Processing 6
Processing 7
Processing 8
Processing 9
Processing 10
All processing complete.
Results: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
*/

parallel

function promisify(callbackFn) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      callbackFn((err, data) => {
        if (err) {
          reject(err);
          return;
        } else {
          resolve(data);
        }
      }, ...args);
    });
  }
}

/**
 * @param {AsyncFunc[]} fns
 * @return {Function}
 */

function parallel(fns) {
  return function (callbackFn, ...args) {
    return Promise.all(fns.map((fn) => promisify(fn)(...args)))
      .then((data) => callbackFn(undefined, data))
      .catch((err) => callbackFn(err, undefined));
  }
}

// Usage example
function asyncFunc1(callback, input) {
  setTimeout(() => {
    callback(null, input * 2);
  }, 1000);
}

function asyncFunc2(callback, input) {
  setTimeout(() => {
    callback(null, input + 10);
  }, 2000);
}

function asyncFunc3(callback, input) {
  setTimeout(() => {
    callback(null, input * input);
  }, 3000);
}

const asyncFunctions = [asyncFunc1, asyncFunc2, asyncFunc3];
const parallelExecution = parallel(asyncFunctions);

parallelExecution((err, results) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('Results:', results);
  }
}, 5); // => Results: [ 10, 15, 25 ]

Parallel downloads

const URL_ARR = [
  'https://fastly.picsum.photos/id/0/5000/3333.jpg?hmac=_j6ghY5fCfSD6tvtcV74zXivkJSPIfR9B8w34XeQmvU',
  'https://fastly.picsum.photos/id/1/5000/3333.jpg?hmac=Asv2DU3rA_5D1xSe22xZK47WEAN0wjWeFOhzd13ujW4',
  'https://fastly.picsum.photos/id/2/5000/3333.jpg?hmac=_KDkqQVttXw_nM-RyJfLImIbafFrqLsuGO5YuHqD-qQ',
  'https://fastly.picsum.photos/id/3/5000/3333.jpg?hmac=GDjZ2uNWE3V59PkdDaOzTOuV3tPWWxJSf4fNcxu4S2g'
];

function fetchData(url) {
  return fetch(url)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`Error: ${response.status}`);
      }

      return response.blob();
    })
    .catch((err) => {
      throw new Error('Error');
    });
}

Promise.all(URL_ARR.map(fetchData))
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.log(err);
  });
/*
[
  Blob { size: 490823, type: 'image/jpeg' },
  Blob { size: 417790, type: 'image/jpeg' },
  Blob { size: 451977, type: 'image/jpeg' },
  Blob { size: 395440, type: 'image/jpeg' }
]
*/

Ping and Calc

function ping(delay) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('Ping successful');
    }, delay);
  });
}

function calc(interval) {
  let start = Date.now();
  let count = 0;
  let timerId = null;

  function loop() {
    const drift = Date.now() - start - count * interval;
    count += 1;

    timerId = setTimeout(async () => {
      const result = await ping(1000);
      console.log(result);

      const elapsedTime = Math.floor((Date.now() - start) / 1000);
      console.log(`Elapsed time: ${elapsedTime} seconds`);

      loop();
    }, interval - drift);
  }

  loop();

  return {
    clear: () => {
      clearTimeout(timerId);
      console.log('Ping calculation aborted.');
    }
  };
}

// Example usage:
const pingCalculator = calc(5000);

setTimeout(() => {
  pingCalculator.clear();
}, 20000); // Stops after 20 seconds

/*
Ping successful
Elapsed time: 6 seconds
Ping successful
Elapsed time: 11 seconds
Ping successful
Elapsed time: 16 seconds
Ping calculation aborted.
*/

Promise merge

function isPlainObject(value) {
  // For null and undefined
  if (value == null) {
    return false;
  }

  const prototype = Object.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}

function mergeResult(result1, result2) {
  try {
    if (typeof result1 === 'number' && typeof result2 === 'number') {
      return result1 + result2;
    }

    if (typeof result1 === 'string' && typeof result2 === 'string') {
      return result1 + result2;
    }

    if (Array.isArray(result1) && Array.isArray(result2)) {
      return [...result1, ...result2];
    }

    if (isPlainObject(result1) && isPlainObject(result2)) {
      return { ...result1, ...result2 };
    }

    throw 'Unsupported data types';
  } catch {
    throw 'Unsupported data types';
  }
}

/**
 * @param {Promise} p1
 * @param {Promise} p2
 * @return {Promise<any>}
 */
function promiseMerge(p1, p2) {
  let unresolved = 2;
  let p1Result;
  let p2Result;

  return new Promise((resolve, reject) => {
    function then() {
      unresolved -= 1;
      if (!unresolved) {
        resolve(mergeResult(p1Result, p2Result));
      }
    }

    p1.then((result) => {
      p1Result = result;
      then();
    }).catch(reject);

    p2.then((result) => {
      p2Result = result;
      then();
    }).catch(reject);
  });
}

// Usage example

const p1 = Promise.resolve(10);
const p2 = Promise.resolve(20);

promiseMerge(p1, p2)
  .then((result) => {
    console.log(result); // => 30
  });

Promise scheduler

class Scheduler {
  constructor(concurrencyLimit) {
    this.taskQueue = [];
    this.concurrencyLimit = concurrencyLimit;
    this.runningTasks = 0;
  }

  addTask(delay, taskId) {
    const task = () => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(`Executing task: ${taskId}`);
          resolve();
        }, delay);
      });
    }

    this.taskQueue.push(task);
  }

  async start() {
    console.log(`Starting scheduler with concurrency limit: ${this.concurrencyLimit}`);
    for (let i = 0; i < this.concurrencyLimit; i += 1) {
      this.executeNextTask();
    }
  }

  async executeNextTask() {
    if (
      this.taskQueue.length === 0 ||
      this.runningTasks >= this.concurrencyLimit
    ) {
      return;
    }

    this.runningTasks += 1;
    const task = this.taskQueue.shift();

    try {
      await task();
    } catch (err) {
      console.error(`Task error: ${err.message}`);
    } finally {
      this.runningTasks -= 1;
      this.executeNextTask();
    }
  }

  get pendingTasksCount() {
    return this.taskQueue.length;
  }

  get activeTasksCount() {
    return this.runningTasks;
  }
}

// Usage example
const scheduler = new Scheduler(2);

scheduler.addTask(1000, "Task 1");
scheduler.addTask(500, "Task 2");
scheduler.addTask(300, "Task 3");
scheduler.addTask(400, "Task 4");

scheduler.start();

setInterval(() => {
  console.log(`Active tasks: ${scheduler.activeTasksCount}, Pending tasks: ${scheduler.pendingTasksCount}`);
}, 500);

/*
Starting scheduler with concurrency limit: 2
Executing task: Task 2
Active tasks: 2, Pending tasks: 1
Executing task: Task 3
Executing task: Task 1
Active tasks: 1, Pending tasks: 0
Executing task: Task 4
Active tasks: 0, Pending tasks: 0
Active tasks: 0, Pending tasks: 0
Active tasks: 0, Pending tasks: 0
*/

Promise time limit

/**
 * @param {Function} fn
 * @param {number} t
 * @return {Function}
 */

function timeLimit (fn, t) {
  return function(...args) {
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => {
        reject('Time Limit Exceeded');
      }, t);
    });

    const fnPromise = fn(...args);

    return Promise.race([timeoutPromise, fnPromise]);
  }
};

// Usage example
const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 1000);
limited(1500).catch(console.log); // => "Time Limit Exceeded" at t=1000ms

Promisify

/**
 * @callback fn
 * @returns Function
 */

function promisify(fn) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      fn.call(this, ...args, (err, result) => {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      });
    });
  }
}

// Usage example
function foo(url, options, callback) {
  apiCall(url, options)
    .then((data) => callback(null, data))
    .catch((err) => callback(err));
}

const promisifiedFoo = promisify(foo);
const data = await promisifiedFoo('example.com', { foo: 1 });



/**
 * @callback fn
 * @returns Function
 */
const promisifyCustomSymbol = Symbol.for('util.promisify.custom');

function promisify(fn) {
  if (fn[promisifyCustomSymbol]) {
    return fn[promisifyCustomSymbol];
  }

  return function (...args) {
    return new Promise((resolve, reject) => {
      fn.call(this, ...args, (err, result) => {
        if (result) {
          resolve(result);
        } else {
          reject(err);
        }
      });
    });
  }
}

// Usage example
function foo(url, options, callback) {
  apiCall(url, options)
    .then((data) => callback(null, data))
    .catch((err) => callback(err));
}

const promisifiedFoo = promisify(foo);
const data = await promisifiedFoo('example.com', { foo: 1 });

race

function promisify(callbackFn) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      callbackFn((err, data) => {
        if (err) {
          reject(err);
          return;
        } else {
          resolve(data);
        }
      }, ...args);
    });
  }
}

/**
 * @param {AsyncFunc[]} fns
 * @return {Function}
 */

function race(fns) {
  return function (callbackFn, ...args) {
    return Promise.race(fns.map((fn) => promisify(fn)(...args)))
      .then((data) => callbackFn(undefined, data))
      .catch((err) => callbackFn(err, undefined));
  }
}

// Usage example
function asyncFunc1(callback, input) {
  setTimeout(() => {
    callback(null, input * 2);
  }, 1000);
}

function asyncFunc2(callback, input) {
  setTimeout(() => {
    callback(null, input + 10);
  }, 2000);
}

function asyncFunc3(callback, input) {
  setTimeout(() => {
    callback(null, input * input);
  }, 3000);
}

const asyncFunctions = [asyncFunc1, asyncFunc2, asyncFunc3];
const raceExecution = race(asyncFunctions);

raceExecution((err, results) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('Results:', results);
  }
}, 5); // => Results: 10

Retry

const URL = 'https://jsonplaceholder.typicode.com/posts';

function fetchWithRetry(url, maxRetries) {
  return new Promise((resolve, reject) => {
    let retries = 0;

    function fetchData(url) {
      fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
          }

          return response.json();
        })
        .then((data) => {
          resolve(data);
        })
        .catch((err) => {
          retries += 1;
          if (retries >= maxRetries) {
            reject(new Error(`Max retries reached. Last error: ${err.message}`));
          } else {
            console.log(`Request failed, retrying... (${retries}/${maxRetries})`);
            fetchData(url);
          }
        });
    }

    fetchData(url);
  });
}

fetchWithRetry(URL, 5)
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.log(err);
  });

Sequence

function promisify(callbackFn) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      callbackFn((err, data) => {
        if (err) {
          reject(err);
          return;
        } else {
          resolve(data);
        }
      }, ...args);
    });
  }
}

/**
 * @param {AsyncFunc[]} fns
 * @return {Function}
 */

function sequence(fns) {
  const promises = fns.map(promisify);

  return async function (callbackFn, ...args) {
    try {
      let result = args;
      for (const promise of promises) {
        result = await promise(...result);
        result = [result];
      }
      callbackFn(undefined, result[0]);
    } catch (err) {
      callbackFn(err, undefined);
    }
  }
}

// Usage example
function asyncFunc1(callback, x, y) {
  setTimeout(() => {
    callback(null, x + y);
  }, 1000);
}

function asyncFunc2(callback, sum) {
  setTimeout(() => {
    callback(null, sum * 2);
  }, 1000);
}

function asyncFunc3(callback, result) {
  setTimeout(() => {
    callback(null, result + 10);
  }, 1000);
}


const asyncFunctions = [asyncFunc1, asyncFunc2, asyncFunc3];
const sequentialExecution = sequence(asyncFunctions);

console.log("Starting sequential execution...");
sequentialExecution((err, result) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('Final Result:', result);
  }
}, 5, 3); 
/*
=> Starting sequential execution...
=> Final Result: 26 (after about 3 seconds)
*/

Sequential async

function asyncOp1(delay) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('async1');
      resolve();
    }, delay);
  });
}

function asyncOp2(delay) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('async2');
      resolve();
    }, delay);
  });
}

async function sequence() {
  try {
    await asyncOp1(2000);
    await asyncOp2(2000);
    console.log('finish');
  } catch (err) {
    console.log(err);
  }
}

sequence();

Sleep

/**
 * @param {number} duration
 * @return {Promise<void>}
 */

async function sleep(duration) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, duration);
  });
}

// Usage example
async function greeting() {
  console.log('Hello!');
  await sleep(2000);
  console.log('Bye.'); // Only logs after 2000 milliseconds (2 seconds)
}

greeting();
// t = 0: Hello!
// t = 2000: Bye.

Throttle promises

/**
 * @param {() => Promise<any>} fns 
 * @param {number} max 
 * @return {Promise}
 */

function throttlePromises(fns, max) {
  const results = [];

  async function doWork(iterator) {
    for (let [index, element] of iterator) {
      const result = await element();
      results[index] = result;
    }
  }

  const iterator = Array.from(fns).entries();
  const workers = Array(max).fill(iterator).map(doWork);

  return Promise.all(workers).then(() => results);
}

// Usage example
const asyncFunctions = [
  () => new Promise(resolve => setTimeout(() => resolve('Task 1'), 1000)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 2'), 1500)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 3'), 800)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 4'), 1200)),
  () => new Promise(resolve => setTimeout(() => resolve('Task 5'), 900))
];

const maxConcurrent = 2;

throttlePromises(asyncFunctions, maxConcurrent)
  .then(results => {
    console.log('All tasks completed');
    console.log('Results:', results);
  })
  .catch(error => {
    console.error('An error occurred:', error);
  });

// All tasks completed
// Results: ['Task 1', 'Task 2', 'Task 3', 'Task 4', 'Task 5']

Traffic light

function red() {
  console.log('red');
}

function green() {
  console.log('green');
}

function yellow() {
  console.log('yellow');
}

const colorActions = {
  red,
  green,
  yellow,
}

function trafficLight(delay, color) {
  return new Promise((resolve) => {
    setTimeout(() => {
      if (colorActions[color]) {
        colorActions[color]();
      } else {
        console.warn(`Unknown color: ${color}`);
      }
      resolve();
    }, delay);
  });
}

// Usage example
async function trafficRunner() {
  const trafficSequence = [
    { delay: 1000, color: 'red' },
    { delay: 2000, color: 'green' },
    { delay: 3000, color: 'yellow' },
  ]

  while (true) {
    for (const { delay, color } of trafficSequence) {
      await trafficLight(delay, color);
    }
  }
}

trafficRunner();

Reference


This content originally appeared on DEV Community and was authored by Mitchell


Print Share Comment Cite Upload Translate Updates
APA

Mitchell | Sciencx (2024-11-04T03:23:16+00:00) Promise – JavaScript challenges. Retrieved from https://www.scien.cx/2024/11/04/promise-javascript-challenges/

MLA
" » Promise – JavaScript challenges." Mitchell | Sciencx - Monday November 4, 2024, https://www.scien.cx/2024/11/04/promise-javascript-challenges/
HARVARD
Mitchell | Sciencx Monday November 4, 2024 » Promise – JavaScript challenges., viewed ,<https://www.scien.cx/2024/11/04/promise-javascript-challenges/>
VANCOUVER
Mitchell | Sciencx - » Promise – JavaScript challenges. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/11/04/promise-javascript-challenges/
CHICAGO
" » Promise – JavaScript challenges." Mitchell | Sciencx - Accessed . https://www.scien.cx/2024/11/04/promise-javascript-challenges/
IEEE
" » Promise – JavaScript challenges." Mitchell | Sciencx [Online]. Available: https://www.scien.cx/2024/11/04/promise-javascript-challenges/. [Accessed: ]
rf:citation
» Promise – JavaScript challenges | Mitchell | Sciencx | https://www.scien.cx/2024/11/04/promise-javascript-challenges/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.