Skip to main content

Async

Syntaxes for async await, Promise + then, and handle errors properly

// Await
async function asyncCall() {
try {
const res = await oneSec(1000)
// a good practice to check res.ok as soon as you receive the response from a fetch call,
// bc the `res` body might be invalid JSON, and below `res.json()` will lead to an error
if (!res.ok) throw new Error(res.status) // e.g. res = { ok: false, status: 404, statusText: "Not Found"}
const data = await res.json()
console.log(data)
} catch (err) {
// The above Error will be caught here
// Here we can handle it appropriately, DON'T THROW AGAIN
reportError({ message: getErrorMessage(err) })
}
}

// Promise with `then`
// Thường ko cần param thứ 2 `err`, trừ những lỗi phải dc xử lý ngay lập tức.
oneSec(2000)
.then(
(res) => {
if (!res.ok) throw new Error(res.status)
return res.json()
},
// (err) => 'deal with the error immediately',
)
.then((data) => console.log(data))
.catch((err) => {
reportError({ message: getErrorMessage(err) })
})

function getErrorMessage(error: unknown) {
// `Error` is a built-in type: { name: string; message: string; stack?: string }
if (error instanceof Error) return error.message
return `${error}`
}

const reportError = ({ message }: { message: string }) => {
// send the error to our logging service...
}

Promise explain

// Log 1 3 2
new Promise((resolve) => {
console.log(1)
resolve(2)
}).then((result) => console.log(result))
console.log(3)

// Async function always return a promise. If not, it will be wrapped in a Promise
async function foo() {
return 1
} // Equalivent to this. Note that this doesn't have `async` keyword
function foo2() {
return Promise.resolve(1)
}

// We don't need `async` here because the fn returns a promise
function oneSec(duration) {
return new Promise((resolve, reject) => {
if (duration === 1000)
setTimeout(
// Resolve with `json` method to simulate typical `fetch` response
() => resolve({ json: () => `{ "id": 1, "title": "vip" }` }),
1000,
)
else reject(new RangeError('Error: duration !== 1000'))
})
}

Promise methods

const fetchDetails = async () => {
const fetchPromises = ids.map((id) => fetch(getJobDetailURL(id)))
const responses = await Promise.all(fetchPromises)
const jsonPromises = responses.map((res) => res.json())
const data = await Promise.all(jsonPromises)
}

// .all -> All must fullfill
// .allSettled -> All must settle (fulfilled or rejected)
//. any -> Return the first fulfilled promise
//. race -> Return the first settled promise

Axios vs Fetch

Fetch phải tốn thêm 1 lần .json(), ngoài ra trong các lệnh như POST, PATCH,... phải convert data bằng JSON.stringify. Fetch thì phải check response.ok rồi mới catch error còn Axios thì catch trực tiếp luôn.

fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-type': 'application/json', // `fetch` default is 'text/plain'
// we don't need this in axios because its default is 'application/json'
},
body: JSON.stringify({
email: '@gmail.com',
}),
})
.then((res) => {
if (!res.ok) throw new Error(res.status)
return res.json()
})
.then((data) => console.log(data))
.catch((err) => console.log(err))

axios
.post('https://jsonplaceholder.typicode.com/posts', {
email: '@gmail.com',
})
.then((res) => console.log(res.data))
.catch((error) => console.log(error))