0

I have the following code below. What i want to do is handle the network error case and the returned HTTP server error cases separately.

fetch("$imageUploadUrl", {
          method: "POST",
          mode: "same-origin",
          cache: "no-store",
          credentials: "same-origin",
          redirect: "error",
          referrer: "origin",
          body: formData
      }).catch(function(error) {
        failure("There was an error while uploading the image");
      }).then(function(response) {
          if (response.ok){
            return Promise.resolve(response.json());
        } else {
            return Promise.reject(response.text())
        }
      }).then(function(result) {
        success(result.location);
      }).catch(function(errorText) {
          return failure (errorText);
      })

However, unlike Promise.resolve(), Promise.reject() does not wait to resolve the promise from response.text() before returning it. I have managed to receive a resolved promise by adding async/await like that:

fetch("$imageUploadUrl", {
          method: "POST",
          mode: "same-origin",
          cache: "no-store",
          credentials: "same-origin",
          redirect: "error",
          referrer: "origin",
          body: formData
      }).catch(function(error) {
        failure("There was an error while uploading the image");
      }).then(async function(response) {
          if (response.ok){
            return Promise.resolve(response.json());
        } else {
            return Promise.reject(await response.text())
        }
      }).then(function(result) {
        success(result.location);
      }).catch(function(errorText) {
          failure(errorText);
      });

Is this the only way to reach my goal?

I have also tried doing this:

fetch("$imageUploadUrl", {
          method: "POST",
          mode: "same-origin",
          cache: "no-store",
          credentials: "same-origin",
          redirect: "error",
          referrer: "origin",
          body: formData
      }).catch(function(error) {
        failure("There was an error while uploading the image");
      }).then(function(response) {
          if (response.ok){
            return Promise.resolve(response.json());
        } else {
            return Promise.reject(response.text())
        }
      }).then(function(result) {
        success(result.location);
      }).catch(function(textPromise) {
          return textPromise;
      }).then(function(text) {
        console.log(text);
      })

But the final then with the console.log is called always, even when i call Promise.resolve() in the code above it, as it was attached on the promise from fetch function itself. Do you know why this happens.

Lyubomir
  • 140
  • 5
  • 13
  • 2
    BTW, there is no point in returning `Promise.resolve()` from a promise callback; that's already a promise. – SLaks Dec 14 '18 at 15:27
  • 1
    `fetch().catch(x=>something).then(y=>y===something` If you catch a promise then what you return in the catch is the value for the the next `then`. I don't think the code you posted is possible since the catch doesn't return anything so the next then should throw an error `Uncaught TypeError: Cannot read property 'ok' of undefined` – HMR Dec 14 '18 at 15:31
  • Also setting redirect is pointless since it is [read only](https://developer.mozilla.org/en-US/docs/Web/API/Request/redirect) – HMR Dec 14 '18 at 15:36
  • What are `success` and `failure`? This looks a lot like the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it). – Bergi Dec 14 '18 at 17:42
  • 1
    possible duplicate of [fetch: Reject promise with JSON error object](https://stackoverflow.com/q/29473426/1048572) – Bergi Dec 14 '18 at 17:43
  • @Bergi success and failure are functions received as callbacks from tinymce: https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_handler Also thanks for the link, it does seem like an my question. I was trying to find out if the different way resolve and reject work are by intent and if there is a way to resolve the inner promise when rejecting. – Lyubomir Dec 14 '18 at 19:17
  • @LyubomirParvanov Ah, what a pity that tinymce doesn't support returning a promise. I still would recommend creating a promise, and using the callbacks only in the end of the chain as `….then(success, failure);`. Especially the `.catch(function(error) { failure("There was an error while uploading the image"); })` doesn't work - the chain continues with a fulfilled promise after that. – Bergi Dec 15 '18 at 12:21

2 Answers2

2

You can wait for the promise, then reject it:

return response.text().then(text => Promise.reject(text));
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
-2

And what about this version:

const options = {
  method: 'POST',
  mode: 'same-origin',
  cache: 'no-store',
  credentials: 'same-origin',
  referrer: 'origin',
  body: formData
}

async function parseResponse (response) {
  try {
    success(await response.json())
  } catch () {
    failure(await response.text())
  }
}

function parseError (err) {
  failure(`Error uploading file: ${err}`)
}

fetch('$imageUploadUrl', options)
  .then(parseResponse)
  .catch(parseError)
Vladislav Ladicky
  • 2,261
  • 1
  • 11
  • 13