LoginSignup
40
28

More than 5 years have passed since last update.

Uncaught (in promise)の発生条件と抑制方法

Posted at

同期にせよ非同期にせよ、普通にエラーをthrowしてcatchしないでおくとブラウザの開発者ツールのコンソールにエラーとして表示されます。

setTimeout(function() {throw new Error('async')}, 1000);
throw new Error('sync');

// Uncaught Error: sync
// Uncaught Error: async 1秒後

Promiseのエラーは実際はrejectなので、本質的にはErrorがthrowされた状態ではありません。が、親切なコンソールではエラーハンドルを忘れていた場合(promiseがrejectされるまでに、一回もcatchハンドラーが設定されていなかった場合)に以下のように表示されます。

親切なコンソール(FirefoxやChrome)

Promise.reject(new Error('promise!!!'));

// Uncaught (in promise) Error: promise!!!

これは開発中にうっかりcatchし忘れるのを防ぐのに大変便利ですので、基本的に抑制すべきではありません。


しかし、1パターンだけわかっていて抑制したい場合があります。それは「今このpromiseはrejectするが、catchハンドラーがsetされるのはもっと後」という場合です。

var promise = Promise.reject(new Error('promise!!!'));

setTimeout(function() {promise.catch(/* 適切なエラーハンドル */);}, 1000);

// Uncaught (in promise) Error: promise!!!
// 後々エラーハンドルするんだけど、コンソールにはUncaught Errorが出てしまう!

これは「promiseがrejectされるまでに、一回もcatchハンドラーが設定されていなかった場合」に表示されるのですから、以下のように即座に一回promiseをcatchしてしまえば抑制できます。

var promise = Promise.reject(new Error('promise!!!'));

// これで抑制できる!!(後で見る人にとっては意味不明なのでコメントでこの記事のURLを貼っておこう)
promise.catch(function(e) {});

setTimeout(function() {promise.catch(/* 適切なエラーハンドル */);}, 1000);

// なにもでない

なお、似てるようですが下記の書き方は大変まずいです。

var promise = Promise.reject(new Error('promise!!!')).catch(function(e) {});

setTimeout(function() {promise.catch(/* 適切なエラーハンドル…でcatchできない!!! */);}, 1000);

// なにもでない

これだと変数promiseには「エラーをすべて握りつぶした後のpromise」が登録されてしまいます。後続のエラーハンドルが全く機能しなくなってしまうので、絶対にやめましょう。

40
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
28