The return purpose is to terminate the execution of the function after the rejection, and prevent the execution of the code after it. 
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
      return; // The function execution ends here 
    }
    resolve(numerator / denominator);
  });
}
In this case it prevents the resolve(numerator / denominator); from executing, which is not strictly needed. However, it's still preferable to terminate the execution to prevent a possible trap in the future. In addition, it's a good practice to prevent running code needlessly. 
Background 
A promise can be in one of 3 states:
- pending - initial state. From pending we can move to one of the other states
 
- fulfilled - successful operation
 
- rejected - failed operation
 
When a promise is fulfilled or rejected, it will stay in this state indefinitely (settled). So, rejecting a fulfilled promise or fulfilling a rejected promise, will have not effect.
This example snippet shows that although the promise was fulfilled after being rejected, it stayed rejected.
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    resolve(numerator / denominator);
  });
}
divide(5,0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
 
 
So why do we need to return?
Although we can't change a settled promise state, rejecting or resolving won't stop the execution of the rest of the function. The function may contain code that will create confusing results. For example:
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    
    console.log('operation succeeded');
    resolve(numerator / denominator);
  });
}
divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
 
 
Even if the function doesn't contain such code right now, this creates a possible future trap. A future refactor might ignore the fact that the code is still executed after the promise is rejected, and will be hard to debug.
Stopping the execution after resolve/reject:
This is standard JS control flow stuff.
- Return after the 
resolve / reject: 
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
      return;
    }
    console.log('operation succeeded');
    resolve(numerator / denominator);
  });
}
divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
 
 
- Return with the 
resolve / reject - since the return value of the callback is ignored, we can save a line by returning the reject/resolve statement: 
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      return reject("Cannot divide by 0");
    }
    console.log('operation succeeded');
    resolve(numerator / denominator);
  });
}
divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
 
 
function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    } else {
      console.log('operation succeeded');
      resolve(numerator / denominator);
    }
  });
}
divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));
 
 
I prefer to use one of the return options as the code is flatter.