How to create a Promise?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Medium
#JavaScript #Asynchronicity #JS Basics

Brief Answer

Promise is created using the new Promise() constructor, which takes an executor function with two parameters: resolve and reject. The executor function executes immediately when the Promise is created and should call resolve(value) on successful completion or reject(error) on error.

Basic syntax:

const myPromise = new Promise((resolve, reject) => {
  // Asynchronous operation
  if (success) {
    resolve(result);
  } else {
    reject(error);
  }
});

Key points:

  • Executor function runs immediately when Promise is created
  • Should call resolve or reject only once
  • Can accept any value as result or error

Full Answer

Creating Promise is a fundamental skill in JavaScript asynchronous programming. Promise represents an object that may complete successfully with some value or complete with an error.

Basic Promise Creation

Promise is created using the new Promise() constructor, which takes one function called the executor function:

const myPromise = new Promise((resolve, reject) => {
  // Executor function
  // resolve(value) - on successful completion
  // reject(error) - on error
});

Simple example

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const randomNumber = Math.random();
    if (randomNumber > 0.5) {
      resolve(`Success! Number: ${randomNumber}`);
    } else {
      reject(new Error(`Error! Number too small: ${randomNumber}`));
    }
  }, 1000);
});
 
// Usage
promise
  .then(result => console.log(result))
  .catch(error => console.error(error.message));

Executor Function Parameters

resolve(value)

The resolve function is called on successful completion of the operation:

const successPromise = new Promise((resolve, reject) => {
  // Simulating asynchronous operation
  setTimeout(() => {
    const data = { id: 1, name: 'User' };
    resolve(data); // Pass the result
  }, 1000);
});
 
successPromise.then(user => {
  console.log('Received user:', user);
});

reject(error)

The reject function is called on error in the operation:

const errorPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const errorMessage = 'Network error';
    reject(new Error(errorMessage)); // Pass the error
  }, 1000);
});
 
errorPromise.catch(error => {
  console.error('An error occurred:', error.message);
});

Practical Examples of Promise Creation

Wrapper for XMLHttpRequest

function fetchUrl(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(`HTTP Error: ${xhr.status}`));
      }
    };
    
    xhr.onerror = function() {
      reject(new Error('Network error'));
    };
    
    xhr.send();
  });
}
 
// Usage
fetchUrl('/api/data')
  .then(data => console.log('Data received:', data))
  .catch(error => console.error('Error:', error.message));

Wrapper for FileReader

function readFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    
    reader.onload = function(event) {
      resolve(event.target.result);
    };
    
    reader.onerror = function(error) {
      reject(new Error('File read error'));
    };
    
    reader.readAsText(file);
  });
}
 
// Usage
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', function(event) {
  const file = event.target.files[0];
  if (file) {
    readFile(file)
      .then(content => console.log('File content:', content))
      .catch(error => console.error('Error:', error.message));
  }
});

Converting callback functions

// Original function with callback
function delayCallback(ms, callback) {
  setTimeout(() => {
    callback(null, `Passed ${ms} milliseconds`);
  }, ms);
}
 
// Converting to Promise
function delayPromise(ms) {
  return new Promise((resolve, reject) => {
    delayCallback(ms, (error, result) => {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
  });
}
 
// Usage
delayPromise(2000)
  .then(message => console.log(message))
  .catch(error => console.error(error));

Important Rules When Creating Promises

1. Calling resolve/reject only once

const correctPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('First call'); // Only this call matters
    resolve('Second call'); // Ignored
  }, 1000);
});
 
// ❌ Incorrect - multiple calls
const wrongPromise = new Promise((resolve, reject) => {
  resolve('First result');
  reject('Error'); // Ignored
});

2. Exception handling in executor function

// ❌ Exception may be lost
const unsafePromise = new Promise((resolve, reject) => {
  throw new Error('Error in executor function');
  // This exception won't be caught!
});
 
// ✅ Proper exception handling
const safePromise = new Promise((resolve, reject) => {
  try {
    // Code that may throw exception
    const result = riskyOperation();
    resolve(result);
  } catch (error) {
    reject(error);
  }
});
 
// Or using .catch()
unsafePromise.catch(error => {
  console.error('Caught exception:', error.message);
});

3. Asynchronous execution of executor function

console.log('1. Before creating Promise');
 
const promise = new Promise((resolve, reject) => {
  console.log('2. Inside executor function');
  setTimeout(() => {
    console.log('4. Asynchronous operation completed');
    resolve('Result');
  }, 1000);
});
 
console.log('3. After creating Promise');
 
promise.then(result => {
  console.log('5. Received result:', result);
});
 
// Output:
// 1. Before creating Promise
// 2. Inside executor function
// 3. After creating Promise
// 4. Asynchronous operation completed
// 5. Received result: Result

Common Mistakes and Solutions

1. Incorrect argument passing

// ❌ Incorrect - passing multiple arguments
const badPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('first', 'second', 'third'); // Only 'first' will be passed
  }, 1000);
});
 
// ✅ Correct - passing object
const goodPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({
      first: 'first',
      second: 'second',
      third: 'third'
    });
  }, 1000);
});

2. Forgotten return in chain

// ❌ Incorrect - losing Promise in chain
function processData() {
  return new Promise((resolve, reject) => {
    getData()
      .then(data => {
        // Forgot return
        transformData(data); // This is not a Promise!
      })
      .then(result => {
        // result will be undefined
        resolve(result);
      });
  });
}
 
// ✅ Correct - returning Promise
function processData() {
  return new Promise((resolve, reject) => {
    getData()
      .then(data => {
        return transformData(data); // Return Promise
      })
      .then(result => {
        resolve(result);
      });
  });
}

Best Practices

  1. Always call resolve or reject — once and only once
  2. Use Error objects — for passing errors through reject
  3. Handle exceptions — in executor function with try/catch
  4. Return Promise from functions — to maintain chain
  5. Use async/await — for more readable code when working with Promise

Key Features of Promise Creation

  1. Immediate execution — executor function runs immediately
  2. Single completion — Promise can be completed only once
  3. Immutable state — after completion state doesn’t change
  4. Asynchronous handlers — then/catch execute asynchronously

Creating Promise is an important skill for working with asynchronous code in JavaScript. Understanding the proper way to create Promise allows you to create more reliable and predictable asynchronous code.


Want more articles to prepare for interviews? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪