Nếu bạn là một lập trình viên JS, chắc hẳn Promise đã quá quen thuộc rồi. Bình thường bạn sẽ xử lý khi nó trả về lỗi như thế nào ? Ở bài viết này, chúng ta cùng tìm hiểu về nó nhé.
1. Xử lý lỗi với .catch
Giả sử có 1 đoạn như thế này, bạn đã xử lý đủ cho cả case thành công và thất bại của promise (khi promise bị reject hoặc một lỗi nào đó xuất hiện)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token keyword">function</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">var</span> myFunc <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">myFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// code generates an error</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> firstName<span class="token operator">:</span> <span class="token string">'Trang'</span><span class="token punctuation">,</span> lastName<span class="token operator">:</span> <span class="token string">'Nguyen'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">profile</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>profile<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'An error has occur: '</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> |
myFunc()
thực tế không phải là function. Đây chính là phần gây ra lỗi. Vì bạn đã có đoạn xử lý lỗi nên tất nhiên, bạn sẽ nhận được dòng log in ra lỗi bình thường như thế này.
1 2 | An error has occur: TypeError: myFunc is not a function |
Và bây giờ, thử thay đổi một chút nhé. Hãy đặt vị trí dòng lỗi khác đi, trong then() của promise như thế này.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">function</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> firstName<span class="token operator">:</span> <span class="token string">'Trang'</span><span class="token punctuation">,</span> lastName<span class="token operator">:</span> <span class="token string">'Nguyen'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">profile</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">var</span> myFunc <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">myFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// code generates an error</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>profile<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'An error has occur: '</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> |
Và lúc này, phần xử lý để in ra thông báo lỗi của bạn đã không được trigger nữa, bạn nhận được kết quả như thế này.
1 2 | UnhandledPromiseRejectionWarning: TypeError: myFunc is not a function |
Hiểu đơn giản thì do phần bạn đang dùng để xử lý lỗi (error) => {}
chỉ bắt những trường hợp mà chính Promise đó trả về lỗi thôi. Tại case này thì Promise đã trả về, sau đó nó lại có 1 đoạn code khác gây lỗi dẫn đến promise bị reject. Vậy giờ muốn xử lý nó thì phải làm sao?
Hãy nhớ đến try...catch
? OK, ứng dụng thôi nào. Bạn chỉ cần sửa lại thành
1 2 3 4 5 6 7 8 9 | <span class="token comment">// Example 1.1</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">profile</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">var</span> myFunc <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">myFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// code generates an error</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>profile<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'An error has occur: '</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> |
Đoạn code dưới thực thi promise và hãy hiểu .catch
có nghĩa là sẽ có một try...catch
ngầm xung quanh nó.
Khi chúng ta ném ra một lỗi trong .then, promise sẽ bị reject, do đó sẽ nhảy đến phần xử lý lỗi gần nhất.
Lỗi ở đây không nhất thiết phải là một lỗi được reject rõ ràng, nó có thể là các lỗi ngẫu nhiên trong trình xử lý.
1 2 3 4 5 6 7 8 9 | <span class="token comment">// Example 1.2</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">profile</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'error nay'</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>profile<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'An error has occur: '</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> |
1 2 3 4 5 6 7 8 9 10 | <span class="token comment">// Example 1.3</span> <span class="token function">getProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">profile</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'error nay'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>profile<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'An error has occur: '</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> |
Ở cả 3 trường hợp 1.1, 1.2, 1.3, lỗi đều được xử lý và in ra thông báo cho người dùng.
Vì vậy hãy luôn nhớ đến .catch()
khi dùng promise nhé.
Với chuỗi promise liên tiếp
.catch
không nhất thiết phải luôn theo kèm 1 .then
. Nó có thể xuất hiện sau một hoặc nhiều .then
Vậy nếu bạn có một chuỗi promise, làm cách nào để xử lý khi đang thực hiện chúng thì xảy ra một lỗi nào đó lỗi.
Cách đơn giản nhất là bắt tất cả các lỗi ở .catch()
cuối cùng trong chuỗi promise. Với cách này, nếu bất cứ promise nào trả về reject (có thể do lỗi mạng hoặc json không hợp lệ hoặc bất cứ lỗi gì), trình thực thi sẽ nhảy đến phần xử lý lỗi gần nhất và .catch
sẽ trigger được chúng.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'/article/promise-chaining/user.json'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.github.com/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>user<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">githubUser</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> img <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'img'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> img<span class="token punctuation">.</span>src <span class="token operator">=</span> githubUser<span class="token punctuation">.</span>avatar_url<span class="token punctuation">;</span> img<span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"promise-avatar-example"</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>img<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> img<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">resolve</span><span class="token punctuation">(</span>githubUser<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> <span class="token function">alert</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
2. Ném lại lỗi
Như đã đề cập .catch
ở cuối chuỗi tương tự như try..catch
. Chúng ta có thể có nhiều .then
và sau đó sử dụng một .catch
duy nhất ở cuối để xử lý lỗi trong tất cả chúng.
Với try ... catch
, chúng ta có thể phân tích lỗi rồi ném lại chúng nếu nó chưa được xử lý, thì tương tự với promise cũng vậy.
Nếu bạn ném một lỗi trong .catch
, nó sẽ được chuyển đến trình xử lý lỗi gần nhất tiếp theo. Và nếu bạn xử lý chúng và kết thúc một cách bình thường (không có lỗi gì nữa), nó sẽ tiếp tục nhảy đến phần xử lý thành công tiếp theo, ở đây là .then()
1 2 3 4 5 6 7 8 9 10 11 | <span class="token comment">// the execution: catch -> then</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"The error is handled, continue normally"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Next successful handler runs"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Ở đây .catch
đã được kết thúc bình thường. Vì vậy xử lý tiếp theo .then
sẽ tiếp tục được gọi.
Một ví dụ khác với .catch()
. Phần xử lý ( * ) bắt các lỗi nhưng không thể xử lý chúng (trong ví dụ này là chỉ xử lý lỗi dạng URIError), vì vậy nó lại ném ra lỗi một lần nữa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token comment">// the execution: catch -> catch</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// (*)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error <span class="token keyword">instanceof</span> <span class="token class-name">URIError</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// handle it</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Can't handle such error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">throw</span> error<span class="token punctuation">;</span> <span class="token comment">// throwing this or another error jumps to the next catch</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* doesn't run here */</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// (**)</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The unknown error has occurred: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// don't return anything => execution goes the normal way</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Trình thực thi sẽ nhảy từ .catch ( * ) đầu tiên đến .catch( ** ) là phần xử lý gần nhất tiếp theo.
3. Unhandled rejections
Chuyện gì sẽ xảy ra nếu một lỗi xảy ra nhưng không được xử lý. Giả sử, bạn đã quên thêm .catch
vào cuối chuỗi như dưới đây:
1 2 3 4 5 6 7 | <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">noSuchFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Error here (no such function)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// successful promise handlers, one or more</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// without .catch at the end!</span> |
Trong trường hợp có lỗi, promise sẽ bị reject, việc thực thi sẽ được chuyển đến phần xử lý rejection gần nhất. Nhưng ở đây thì không có, do đó lỗi đã bị “stuck”, không có đoạn code nào xử lý nó dẫn đến chương trình bị lỗi và đứng tại đó. JavaScript theo dõi những rejection như vậy và tạo ra global error trong trường hợp đó. Bạn sẽ thấy dòng thông báo lỗi đỏ ở console.
Để xử lý chúng thì ở browser, chúng ta có thể bắt các lỗi như vậy bằng cách sử dụng unhandledrejection
:
1 2 3 4 5 6 7 8 9 10 | window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'unhandledrejection'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// the event object has two special properties:</span> <span class="token function">alert</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>promise<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [object Promise] - the promise that generated the error</span> <span class="token function">alert</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Error: Whoops! - the unhandled error object</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// no catch to handle the error</span> |
Nhờ vậy, nếu lỗi xảy ra và không được .catch
, bạn vẫn có thể thông báo cho người dùng đã có lỗi xảy ra hoặc có thể báo cáo sự cố cho máy chủ.
4. Lỗi trong setTimeout
Bạn nghĩ thế nào về ví dụ này ? .catch
liệu có được bắt được lỗi này không ?
1 2 3 4 5 6 | <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Whoops!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>alert<span class="token punctuation">)</span><span class="token punctuation">;</span> |
Và câu trả lời là KHÔNG
Như đã đề cập ở trên, một try... catch
ngầm sẽ hoạt động. Mà try-catch
lại là đồng bộ. (Bạn có thể đọc thêm ở đây)
Nên với những ngoại lệ xảy ra trong “scheduled” code (như setTimeout
, setInterval
) nó sẽ không thể bắt được.
Để xử lý trường hợp này, bạn có thể để try...catch
ở bên trong setTimeout
callback
1 2 3 4 5 6 7 8 9 10 | new Promise(function(resolve, reject) { setTimeout(() => { try { throw new Error("Whoops!"); } catch(error) { console.log('Error in setTimeout: ', error); }; }, 1000); }).catch(e => console.log('Error: ', e)); |
Tổng kết
.catch
xử lý các lỗi trong promise: khi gọi reject(), hoặc khi một lỗi nào đó được ném ra trong quá trình xử lý.- Nên đặt
.catch
ở vị trí chính xác, nơi mà bạn muốn xử lý lỗi và biết cách xử lý chúng ra sao. Khi xử lý chúng ta nên phân tích các loại lỗi (bằng cách xử dụng các custom error class) hoặc ném lại chúng. - Trong mọi trường hợp, chúng ta nên có
unhandledrejection
(cho browsers, và những môi trường tương tự) để theo dõi những lỗi không được xử lý và để thông báo cho người dùng (hoặc máy chủ) về chúng, từ đó, app của chúng ta sẽ tránh những lỗi crash.
Bài viết đến đây là hết, cảm ơn các bạn đã theo dõi nhé.