I've written an ES6 function using the new fetch() API and returning a new resolved promise with a data object or a rejected promise with an error subclass.
I'm pretty new to both ES6 and Promises, and it looks a little unwieldy, so I'm wondering if there's a better way. I'm also wondering about how this relates to the "explicit promise construction antipattern".
Any suggestions for how to improve or simplify?
function get(url) {
console.log('Making fetch() request to: ' + url);
let promise = new Promise((resolve, reject) => {
fetch(url).then(response => {
if (response.ok) {
const contentType = response.headers.get('Content-Type') || '';
if (contentType.includes('application/json')) {
response.json().then(obj => {
resolve(obj);
}, error => {
reject(new ResponseError('Invalid JSON: ' + error.message));
});
} else if (contentType.includes('text/html')) {
response.text().then(html => {
resolve({
page_type: 'generic',
html: html
});
}, error => {
reject(new ResponseError('HTML error: ' + error.message));
});
} else {
reject(new ResponseError('Invalid content type: ' + contentType));
}
} else {
if (response.status == 404) {
reject(new NotFoundError('Page not found: ' + url));
} else {
reject(new HttpError('HTTP error: ' + response.status));
}
}
}, error => {
reject(new NetworkError(error.message));
});
});
return promise;
}
1 Answer 1
A few comments:
1) fetch
already returns a promise, which means this:
new Promise((resolve, reject) => {
return fetch(url).then(response => {
if (response.ok) {
resolve(response)
} else {
reject(new Error('error'))
}
}, error => {
reject(new Error(error.message))
})
})
Is pretty much the same as:
fetch(url).then(response => {
if (response.ok) {
return response
}
return Promise.reject(Error('error'))
}).catch(error => {
return Promise.reject(Error(error.message))
})
2) Keeping this in mind you can simplify your code with early returns and fewer branches:
function get(url) {
return fetch(url).then(response => {
if (response.ok) {
const contentType = response.headers.get('Content-Type') || '';
if (contentType.includes('application/json')) {
return response.json().catch(error => {
return Promise.reject(new ResponseError('Invalid JSON: ' + error.message));
});
}
if (contentType.includes('text/html')) {
return response.text().then(html => {
return {
page_type: 'generic',
html: html
};
}).catch(error => {
return Promise.reject(new ResponseError('HTML error: ' + error.message));
})
}
return Promise.reject(new ResponseError('Invalid content type: ' + contentType));
}
if (response.status == 404) {
return Promise.reject(new NotFoundError('Page not found: ' + url));
}
return Promise.reject(new HttpError('HTTP error: ' + response.status));
}).catch(error => {
return Promise.reject(new NetworkError(error.message));
});
}