Question: Safety of using and approach to "floating" promises

In the MDN Docs it explains,

Important: Always return results, otherwise callbacks won't catch the result of a previous promise (with arrow functions, () => x is short for () => { return x; }). If the previous handler started a promise but did not return it, there's no way to track its settlement anymore, and the promise is said to be "floating".

With this little json file:
{
  "ingredients": "flour,sugar,butter,chocolate"
}

const listOfIngredients = [];
console.clear();
function doSomething() {
  fetch('http://127.0.0.1:4000/test.json')
  .then((res) => res.json())
  .then((data) => {
    data.ingredients.split(',').forEach(i => listOfIngredients.push(i)); 
  // doesn't return
  })
  .then((nothing) => {
    console.log(nothing); // undefined, of course
    console.log(listOfIngredients);
    return "and coconut";
  })
  .then((something) => {
    listOfIngredients.push(something);
    console.log(listOfIngredients);
  });
}
doSomething();

Result:
undefined
['flour', 'sugar', 'butter', 'chocolate']
['flour', 'sugar', 'butter', 'chocolate', 'and coconut']

So, I think that the result of the success callback, (data) => {...} is (said to be) "floating", but that since in this case, the promise returns immediately, the chained (nothing) => {...} and (something) => {...} callbacks succeed.
If I update the (nothing) callback to contain another fetch, that fetch does need to be returned ((nothing) => { return fetch...  otherwise we get ['flour', 'sugar', 'butter', 'chocolate', undefined]. Makes sense.
So, in promise chains, do you only need to return from the callbacks for promise objects that handle asynchronous operations?


Answer:

So, in promise chains, do you only need to return from the callbacks for promise objects that handle asynchronous operations?

You are correct. From the mdn doc you provided:

If the previous handler started a promise but did not return it, there's no way to track its settlement anymore, and the promise is said to be "floating".

Notice in this one:
.then((data) => {
    data.ingredients.split(',').forEach(i => listOfIngredients.push(i)); 
  // doesn't return
  })

you aren't starting a promise so there is no issue.
Floating promises have nothing to do with returning the data but rather returning when the promise resolves you could do something like this for instance:
.then(async res => {
    window.myGlobal = await res.json();
}).then(nothing => /* ... continue */ undefined);

even though we aren't returning the data directly the function provided only resolves when res.json() has finished so we don't have any hanging promises.
Incidentally your example does have a hanging promise: the doSomething function. the doSomething function should be returning the fetch call as in:
function doSomething() {
  return fetch('http://127.0.0.1:4000/test.json')
  /* ... */
}

Note that if you didn't want to return the fetch for some reason you could still avoid the hanging promise by using async/await like:
async function doSomething() {
  await fetch('http://127.0.0.1:4000/test.json')
  /* ... */
}

this is functionally equivalent to the following however:
function doSomething() {
  return fetch('http://127.0.0.1:4000/test.json')
      /* ... your existing .then chain goes here */
      .then(() => undefined)
  }
}

Also note that as mentioned in the comments you are probably doing something really bad if you are writing code this way (not returning the results of asyncronous operations but still wanting to do things after they complete)