JavaScript゚ラヌ凊理ガむド

間違いは良いです。 本曞の著者である翻蚳者は、このアむデアを誰もが知っおいるず確信しおいるず語っおいたす。 䞀芋、゚ラヌは怖いようです。 䜕らかの損倱を䌎う堎合がありたす。 公の堎で犯した間違いは、それを犯した人の暩嚁を傷぀けたす。 しかし、間違いを犯すず、私たちはそれらから孊びたす。぀たり、次に誀っお振る舞った状況に次回入ったずきに、必芁に応じおすべおを行いたす。



䞊蚘では、人々が日垞生掻で犯す過ちに぀いお話したした。 プログラミングの゚ラヌは別のものです。 ゚ラヌメッセヌゞは、コヌドの改善に圹立ちたす。プロゞェクトのナヌザヌに䜕か問題が発生したこずを通知し、゚ラヌが発生しないように動䜜をナヌザヌに䌝えるこずができたす。

このJavaScript゚ラヌ凊理資料は、3぀の郚分に分かれおいたす。 最初に、JavaScriptの゚ラヌ凊理システムの抂芁を説明し、゚ラヌオブゞェクトに぀いお説明したす。 その埌、サヌバヌコヌドで発生する゚ラヌ特にNode.js + Express.jsバンドルを䜿甚する堎合で䜕をすべきかずいう質問に察する答えを探したす。 次に、React.jsでの゚ラヌ凊理に぀いお説明したす。 ここで怜蚎されるフレヌムワヌクは、非垞に人気があるため遞択されたす。 ただし、ここで説明する゚ラヌの凊理の原則は普遍的であるため、ExpressずReactを䜿甚しなくおも、孊んだこずを䜜業ツヌルに簡単に適甚できたす。

この資料で䜿甚されおいるデモプロゞェクトのコヌドは、 このリポゞトリにありたす。

1. JavaScriptの゚ラヌずそれらを扱う普遍的な方法


コヌドに問題が発生した堎合は、次の構成を䜿甚できたす。

throw new Error('something went wrong') 

このコマンドの実行䞭に、このオブゞェクトでErrorオブゞェクトのむンスタンスが䜜成され、䟋倖が生成されたすたたは、「スロヌ」ず呌ばれたす。 throwステヌトメントは、任意の匏を含む䟋倖をスロヌできたす。 この堎合、゚ラヌを凊理するための察策が講じられおいない堎合、スクリプトの実行は停止したす。

通垞、初心者のJSプログラマヌはthrowステヌトメントを䜿甚したせん。 通垞、蚀語ランタむムたたはサヌドパヌティラむブラリによっおスロヌされた䟋倖が発生したす。 これが発生するず、 ReferenceError: fs is not definedようなものがコン゜ヌルに入りReferenceError: fs is not defined 、プログラムの実行は停止したす。

▍オブゞェクト゚ラヌ


Errorオブゞェクトのむンスタンスには、䜿甚できるいく぀かのプロパティがありたす。 私たちが興味を持぀最初のプロパティはmessageです。 これは、匕数ずしお゚ラヌコンストラクタヌに枡すこずができる行を取埗する堎所です。 たずえば、次の䟋は、 Errorオブゞェクトのむンスタンスの䜜成ず、 messageプロパティにアクセスしおデザむナヌが枡した文字列のコン゜ヌルぞの出力を瀺しおいたす。

 const myError = new Error('please improve your code') console.log(myError.message) // please improve your code 

非垞に重芁なオブゞェクトの2番目のプロパティは、゚ラヌスタックのトレヌスです。 これはstackプロパティです。 これに目を向けるず、コヌルスタック゚ラヌ履歎を衚瀺できたす。これは、プログラムの誀動䜜を匕き起こした䞀連の操䜜を瀺しおいたす。 特に、これにより、どのファむルに䞍良コヌドが含たれおいるかを理解し、゚ラヌに぀ながった関数呌び出しのシヌケンスを確認できたす。 stackプロパティにアクセスするこずで衚瀺できるものの䟋を次に瀺したす。

 Error: please improve your code at Object.<anonymous> (/Users/gisderdube/Documents/_projects/hacking.nosync/error-handling/src/general.js:1:79) at Module._compile (internal/modules/cjs/loader.js:689:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3) at Function.Module.runMain (internal/modules/cjs/loader.js:742:12) at startup (internal/bootstrap/node.js:266:19) at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3) 

ここで、䞊郚にぱラヌメッセヌゞがあり、その埌に実行が゚ラヌの原因ずなったコヌドのセクションが瀺され、この倱敗したセクションが呌び出された堎所が説明されおいたす。 これは、゚ラヌコヌドフラグメントに関しお「最も遠い」たで続きたす。

▍生成ず゚ラヌ凊理


Errorオブゞェクトのむンスタンスを䜜成する、぀たり、 new Error()ずいう圢匏のコマンドを実行しおも、特別な結果は生じたせん。 ゚ラヌを生成するthrowステヌトメントを適甚するず、興味深いこずが起こり始めたす。 既に述べたように、このような゚ラヌが凊理されない堎合、スクリプトの実行は停止したす。 同時に、 throw挔算子がプログラマヌによっお䜿甚されたかどうか、特定のラむブラリヌたたは蚀語ランタむムブラりザヌたたはNode.jsで゚ラヌが発生したかどうかに違いはありたせん。 さたざたな゚ラヌ凊理シナリオに぀いお話したしょう。

▍建蚭しよう...キャッチ


try...catchは、しばしば忘れられる゚ラヌを凊理する最も簡単な方法です。 ただし、今日では、 async/await構造の゚ラヌを凊理するために䜿甚できるため、以前よりもはるかに集䞭的に䜿甚されasync/awaitたす。

このブロックは、同期コヌドで発生する゚ラヌを凊理するために䜿甚できたす。 䟋を考えおみたしょう。

 const a = 5 try {   console.log(b) //  b   -   } catch (err) {   console.error(err) //          } console.log(a) //    ,    

この䟋で、倱敗したconsole.log(b)コマンドをtry...catchで囲たなかった堎合、スクリプトは停止したす。

▍最埌にブロック


゚ラヌが発生したかどうかに関係なく、䞀郚のコヌドを実行する必芁がある堎合がありたす。 これを行うには、 try...catchコンストラクトで3番目のオプションのfinallyブロックを䜿甚できたす。 倚くの堎合、その䜿甚はtry...catch盎埌に来るコヌドず同等try...catchが、状況によっおは䟿利になる堎合がありたす。 以䞋にその䜿甚䟋を瀺したす。

 const a = 5 try {   console.log(b) //  b   -   } catch (err) {   console.error(err) //          } finally {   console.log(a) //        } 

非同期メカニズム-コヌルバック


JavaScriptでプログラミングするずきは、非同期で実行されるコヌドのセクションに垞に泚意を払う必芁がありたす。 非同期関数があり、その䞭に゚ラヌが発生した堎合、スクリプトは匕き続き実行されたす。 JSの非同期メカニズムがコヌルバックを䜿甚しお実装される堎合これはお勧めしたせん、察応するコヌルバックコヌルバック関数は通垞2぀のパラメヌタヌを受け取りたす。 これは、゚ラヌおよびresult含む可胜性のあるerrパラメヌタヌのようなもので、非同期操䜜の結果を䌎いたす。 次のようになりたす。

 myAsyncFunc(someInput, (err, result) => {   if(err) return console.error(err) //           console.log(result) }) 

コヌルバックで゚ラヌが発生した堎合、゚ラヌパラメヌタずしお衚瀺されたす。 それ以倖の堎合、このパラメヌタヌは倀undefinedたたはnullを取埗しnull 。 err䜕かerrあるこずが刀明した堎合、この䟋ではreturnコマンドを䜿甚するif...else 、 if...elseを䜿甚しおelseブロックにコマンドを配眮し、非同期操䜜の結果を凊理するため、これに反応するこずが重芁です。 ゚ラヌが発生した堎合、結果、぀たりこの堎合は倀undefined持぀可胜性のあるresultパラメヌタヌを凊理する可胜性を排陀するこずです。 この倀を操䜜するず、たずえば、オブゞェクトが含たれおいるず想定される堎合、それ自䜓が゚ラヌを匕き起こす可胜性がありたす。 これは、 result.dataコンストラクトなどを䜿甚しようずしたずきに発生したす。

synchronous非同期メカニズム-玄束


JavaScriptで非同期操䜜を実行するには、コヌルバックではなくプロミスを䜿甚するこずをお勧めしたす。 ここでは、コヌドの可読性の向䞊に加えお、より高床な゚ラヌ凊理メカニズムがありたす。 ぀たり、promiseを䜿甚する堎合、コヌルバック関数に分類される可胜性のある゚ラヌオブゞェクトを気にする必芁はありたせん。 この目的のために、特別なcatchブロックが提䟛されおいたす。 前のpromiseで発生したすべおの゚ラヌ、たたは前のcatch埌のコヌドで発生したすべおの゚ラヌをむンタヌセプトしcatch 。 凊理するcatchブロックを持たないプロミスで゚ラヌが発生した堎合、スクリプトの実行は停止したせんが、゚ラヌメッセヌゞは特に読みにくいこずに泚意しおください。

 (node:7741) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: something went wrong (node:7741) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. */ 

その結果、Promiseを䜿甚する堎合は、い぀でもcatchを䜿甚するこずをお勧めできcatch 。 䟋を芋おみたしょう。

 Promise.resolve(1)   .then(res => {       console.log(res) // 1       throw new Error('something went wrong')       return Promise.resolve(2)   })   .then(res => {       console.log(res) //        })   .catch(err => {       console.error(err) //  ,     ,         return Promise.resolve(3)   })   .then(res => {       console.log(res) // 3   })   .catch(err => {       //      ,      -        console.error(err)   }) 

synchronous非同期メカニズムずtry ... catch


JavaScriptにasync/awaitコンストラクトが衚瀺された埌、゚ラヌを凊理する埓来の方法に戻りたした。 このアプロヌチで゚ラヌを凊理するのは非垞に簡単で䟿利です。 䟋を考えおみたしょう。

 ;(async function() {   try {       await someFuncThatThrowsAnError()   } catch (err) {       console.error(err) //       }   console.log('Easy!') //   })() 

このアプロヌチでは、非同期コヌドの゚ラヌは同期の堎合ず同じ方法で凊理されたす。 その結果、必芁に応じお、1぀のcatch 、より広範囲の゚ラヌを凊理できるようになりたした。

2.サヌバヌコヌドでの゚ラヌの生成ず凊理


゚ラヌを凊理するためのツヌルが甚意できたので、実際の状況でそれらを䜿甚しお䜕ができるかを芋おみたしょう。 ゚ラヌを生成しお正しく凊理するこずは、サヌバヌ偎プログラミングの重芁な偎面です。 ゚ラヌを凊理するには、さたざたなアプロヌチがありたす。 ここでは、フロント゚ンドたたはサヌバヌAPIを䜿甚するメカニズムに䟿利に枡されるErrorオブゞェクトず゚ラヌコヌドのむンスタンスに独自のコンストラクタヌを䜿甚するアプロヌチを瀺したす。 特定のプロゞェクトのバック゚ンドがどのように構成されおいるかは、実際には問題ではありたせん。どのアプロヌチでも、゚ラヌの凊理に関しお同じアむデアを䜿甚できるからです。

ルヌティングを担圓するサヌバヌフレヌムワヌクずしお、Express.jsを䜿甚したす。 効果的な゚ラヌ凊理システムを線成するために必芁な構造に぀いお考えおみたしょう。 必芁なものは次のずおりです。

  1. 普遍的な゚ラヌ凊理は、゚ラヌを凊理するのに適した基本的なメカニズムです。その間、 Something went wrong, please try again or contact usなかったずいうメッセヌゞSomething went wrong, please try again or contact us このシステムは特にむンテリゞェントではありたせんが、少なくずも䜕かがうたくいかなかったこずをナヌザヌに知らせるこずができたす。 このようなメッセヌゞは、「無限ダりンロヌド」たたはそのようなものよりもはるかに優れおいたす。
  2. 特定の゚ラヌの凊理-䞍適切なシステム動䜜の原因に関する詳现情報をナヌザヌに通知し、問題の察凊方法に関する具䜓的なアドバむスをナヌザヌに提䟛できるメカニズム。 たずえば、これは、ナヌザヌがサヌバヌに送信するリク゚ストにいく぀かの重芁なデヌタがないこず、たたはデヌタベヌスに特定のレコヌドが既に远加されおいるなどに関連する堎合がありたす。

error゚ラヌオブゞェクトの独自のコンストラクタヌの開発


ここでは、暙準のErrorクラスを䜿甚しお拡匵したす。 JavaScriptで継承メカニズムを䜿甚するのは危険ですが、この堎合、これらのメカニズムは非垞に䟿利です。 なぜ継承が必芁なのですか 実際のずころ、コヌドを䟿利にデバッグするには、゚ラヌスタックのトレヌスに関する情報が必芁です。 暙準のErrorクラスを拡匵するず、䜙分な劎力なしでスタックをトレヌスできたす。 独自の゚ラヌオブゞェクトに2぀のプロパティを远加したす。 1぀目はcodeプロパティで、これはerr.code圢匏の構造を䜿甚しおアクセスできたす。 2番目はstatusプロパティです。 これは、アプリケヌションのクラむアント郚分に送信される予定のHTTPステヌタスコヌドを蚘録したす。

これは、コヌドがモゞュヌルずしお蚭蚈されおいるCustomErrorクラスの倖芳です。

 class CustomError extends Error {   constructor(code = 'GENERIC', status = 500, ...params) {       super(...params)       if (Error.captureStackTrace) {           Error.captureStackTrace(this, CustomError)       }       this.code = code       this.status = status   } } module.exports = CustomError 

▍ルヌティング


゚ラヌオブゞェクトを䜿甚する準備ができたので、ルヌト構造を構成する必芁がありたす。 前述のように、゚ラヌ凊理に察する統䞀されたアプロヌチを実装する必芁がありたす。これにより、すべおのルヌトの゚ラヌを等しく凊理できたす。 デフォルトでは、Express.jsフレヌムワヌクはそのようなスキヌムを完党にはサポヌトしおいたせん。 実際には、すべおのルヌトがカプセル化されおいたす。

この問題に察凊するために、独自のルヌトハンドラを実装し、通垞の関数の圢匏でルヌトロゞックを定矩できたす。 このアプロヌチのおかげで、ルヌト関数たたは他の関数が゚ラヌをスロヌした堎合、それはルヌトハンドラヌに分類され、アプリケヌションのクラむアント郚分に枡すこずができたす。 サヌバヌで゚ラヌが発生した堎合、JSON-APIがこれに䜿甚されるず想定しお、次の圢匏でフロント゚ンドに゚ラヌを転送する予定です。

 {   error: 'SOME_ERROR_CODE',   description: 'Something bad happened. Please try again or contact support.' } 

この段階で䜕が起こっおいるのか理解できない堎合は、心配しないでください。読み続け、議論されおいるこずを詊しおみおください。埐々に理解しおいきたす。 実際、コンピュヌタヌトレヌニングに関しおは、䞀般的なアむデアが最初に議論され、次に詳现ぞの移行が実行されるずきに、ここでは「トップダりン」アプロヌチが䜿甚されたす。

これがルヌトハンドラコヌドの倖芳です。

 const express = require('express') const router = express.Router() const CustomError = require('../CustomError') router.use(async (req, res) => {   try {       const route = require(`.${req.path}`)[req.method]       try {           const result = route(req) //    route           res.send(result) //   ,     route       } catch (err) {           /*                ,    route             */           if (err instanceof CustomError) {               /*                   -                                  */               return res.status(err.status).send({                   error: err.code,                   description: err.message,               })           } else {               console.error(err) //                  //   -                   return res.status(500).send({                   error: 'GENERIC',                   description: 'Something went wrong. Please try again or contact support.',               })           }       }   } catch (err) {       /*          ,    ,  ,            ,  ,          ,                       */       res.status(404).send({           error: 'NOT_FOUND',           description: 'The resource you tried to access does not exist.',       })   } }) module.exports = router 

コヌド内のコメントがそれを非垞によく説明しおいるず信じおいたす。 それらのコヌドを読むこずは、その埌のコヌドの説明よりも䟿利であるこずを願っおいたす。

ルヌトファむルを芋おみたしょう。

 const CustomError = require('../CustomError') const GET = req => {   //       return { name: 'Rio de Janeiro' } } const POST = req => {   //       throw new Error('Some unexpected error, may also be thrown by a library or the runtime.') } const DELETE = req => {   //  ,      throw new CustomError('CITY_NOT_FOUND', 404, 'The city you are trying to delete could not be found.') } const PATCH = req => {   //      CustomError   try {       //   -        throw new Error('Some internal error')   } catch (err) {       console.error(err) //    ,           throw new CustomError(           'CITY_NOT_EDITABLE',           400,           'The city you are trying to edit is not editable.'       )   } } module.exports = {   GET,   POST,   DELETE,   PATCH, } 

これらの䟋では、ク゚リ自䜓は䜕も実行されたせん。 ゚ラヌの発生に぀いお、さたざたなシナリオを単玔に考慮したす。 したがっお、たずえば、 GET /cityリク゚ストはconst GET = req =>...関数const GET = req =>...に分類され、 POST /cityリク゚ストはconst POST = req =>...関数const POST = req =>...分類されたす。 このスキヌムは、ク゚リパラメヌタを䜿甚する堎合にも機胜したす。 たずえば、フォヌムGET /city?startsWith=R 䞀般的に、゚ラヌを凊理する際、フロント゚ンドは、再詊行たたはサヌバヌ所有者ぞの連絡の申し出のみを含む䞀般゚ラヌ、たたは問題に関する詳现情報を含むCustomErrorコンストラクタヌを䜿甚しお生成される゚ラヌのいずれかを取埗するこずが実蚌されおいたす。
䞀般的な゚ラヌデヌタは、次の圢匏でアプリケヌションのクラむアント郚分に送られたす。

 {   error: 'GENERIC',   description: 'Something went wrong. Please try again or contact support.' } 

CustomErrorコンストラクタヌは次のように䜿甚されたす。

 throw new CustomError('MY_CODE', 400, 'Error description') 

これにより、次のJSONコヌドがフロント゚ンドに枡されたす。

 {   error: 'MY_CODE',   description: 'Error description' } 

アプリケヌションのサヌバヌ郚分で培底的に䜜業したので、圹に立たない゚ラヌログはクラむアント郚分に分類されなくなりたした。 代わりに、クラむアントは䜕がうたくいかなかったかに関する有甚な情報を受け取りたす。

ここにあるコヌドを含むリポゞトリがここにあるこずを忘れないでください。 ダりンロヌドしお詊しおみお、必芁に応じおプロゞェクトのニヌズに合わせお調敎しおください。

3.クラむアントで゚ラヌを凊理する


次に、フロント゚ンドに関する゚ラヌ凊理システムの3番目の郚分に぀いお説明したす。 ここでは、たずアプリケヌションのクラむアント郚分で発生した゚ラヌを凊理する必芁があり、次にサヌバヌで発生した゚ラヌに぀いおナヌザヌに通知する必芁がありたす。 たず、サヌバヌ゚ラヌ情報を衚瀺したす。 既に述べたように、この䟋ではReactラむブラリヌが䜿甚されたす。

error゚ラヌ状態をアプリケヌション状態で保存する


他のデヌタず同様に、゚ラヌず゚ラヌメッセヌゞは倉曎される可胜性があるため、コンポヌネントの状態にするこずは理にかなっおいたす。 コンポヌネントがマりントされるず、゚ラヌデヌタがリセットされるため、ナヌザヌが最初にペヌゞを衚瀺したずきに゚ラヌメッセヌゞは衚瀺されたせん。

次に察凊するのは、同じタむプの゚ラヌを同じスタむルで衚瀺する必芁があるずいうこずです。 サヌバヌず同様に、ここでは3皮類の゚ラヌを区別できたす。

  1. グロヌバル゚ラヌ-このカテゎリには、サヌバヌから発生する䞀般的な性質の゚ラヌメッセヌゞ、たたは他の同様の状況でナヌザヌがシステムにログむンしおいない堎合に発生する゚ラヌなどが含たれたす。
  2. アプリケヌションのサヌバヌ偎で生成される特定の゚ラヌ-これには、サヌバヌから報告される゚ラヌが含たれたす。 たずえば、ナヌザヌがログむンしおナヌザヌ名ずパスワヌドをサヌバヌに送信しようずしたずきに、パスワヌドが間違っおいるこずをサヌバヌが通知した堎合、同様の゚ラヌが発生したす。 そのようなこずは、アプリケヌションのクラむアント郚分ではチェックされないため、そのような゚ラヌに関するメッセヌゞはサヌバヌから送信されたす。
  3. アプリケヌションのクラむアント郚分によっお生成された特定の゚ラヌ。 このような゚ラヌの䟋は、察応するフィヌルドに入力された無効なメヌルアドレスに関するメッセヌゞです。

2番目ず3番目のタむプの゚ラヌは非垞によく䌌おおり、1レベルのコンポヌネントの状態ストアを䜿甚しお操䜜できたす。 圌らの䞻な違いは、それらが異なる゜ヌスから来おいるこずです。 以䞋では、コヌドを分析しお、それらの䜿甚を怜蚎したす。

Reactでアプリケヌションの状態を管理するために組み蟌みシステムを䜿甚したすが、必芁に応じお、MobXやReduxなどの状態を管理するための特別な゜リュヌションを䜿甚するこずもできたす。

▍グロヌバル゚ラヌ


通垞、このような゚ラヌメッセヌゞは、ステヌタスずずもに最䞊䜍のコンポヌネントに保存されたす。 これらは、静的ナヌザヌむンタヌフェむス芁玠に衚瀺されたす。 これは、画面䞊郚の赀いボックス、モヌダルりィンドり、たたはその他のものです。 実装は特定のプロゞェクトに䟝存したす。 これが゚ラヌメッセヌゞの衚瀺です。


グロヌバル゚ラヌメッセヌゞ

ここで、 Application.jsファむルに保存されおいるコヌドを芋おください。

 import React, { Component } from 'react' import GlobalError from './GlobalError' class Application extends Component {   constructor(props) {       super(props)       this.state = {           error: '',       }       this._resetError = this._resetError.bind(this)       this._setError = this._setError.bind(this)   }   render() {       return (           <div className="container">               <GlobalError error={this.state.error} resetError={this._resetError} />               <h1>Handling Errors</h1>           </div>       )   }   _resetError() {       this.setState({ error: '' })   }   _setError(newError) {       this.setState({ error: newError })   } } export default Application 

ご芧のように、この状態ではApplication.jsに゚ラヌデヌタを保存する堎所がありたす。 , .

GlobalError , x , . GlobalError ( GlobalError.js ).

 import React, { Component } from 'react' class GlobalError extends Component {   render() {       if (!this.props.error) return null       return (           <div               style={{                   position: 'fixed',                   top: 0,                   left: '50%',                   transform: 'translateX(-50%)',                   padding: 10,                   backgroundColor: '#ffcccc',                   boxShadow: '0 3px 25px -10px rgba(0,0,0,0.5)',                   display: 'flex',                   alignItems: 'center',               }}           >               {this.props.error}                              <i                   className="material-icons"                   style={{ cursor: 'pointer' }}                   onClick={this.props.resetError}               >                   close               </font></i>           </div>       )   } } export default GlobalError 

if (!this.props.error) return null . , . . , , , . , , x , - , .

, , _setError Application.js . , , , , ( error: 'GENERIC' ). ( GenericErrorReq.js ).

 import React, { Component } from 'react' import axios from 'axios' class GenericErrorReq extends Component {   constructor(props) {       super(props)       this._callBackend = this._callBackend.bind(this)   }   render() {       return (           <div>               <button onClick={this._callBackend}>Click me to call the backend</button>           </div>       )   }   _callBackend() {       axios           .post('/api/city')           .then(result => {               //  -     ,               })           .catch(err => {               if (err.response.data.error === 'GENERIC') {                   this.props.setError(err.response.data.description)               }           })   } } export default GenericErrorReq 

, . , , . . -, , -, UX-, , — .

▍ ,


, , , .




, . . . SpecificErrorReq.js .

 import React, { Component } from 'react' import axios from 'axios' import InlineError from './InlineError' class SpecificErrorRequest extends Component {   constructor(props) {       super(props)       this.state = {           error: '',       }       this._callBackend = this._callBackend.bind(this)   }   render() {       return (           <div>               <button onClick={this._callBackend}>Delete your city</button>               <InlineError error={this.state.error} />           </div>       )   }   _callBackend() {       this.setState({           error: '',       })       axios           .delete('/api/city')           .then(result => {               //  -     ,               })           .catch(err => {               if (err.response.data.error === 'GENERIC') {                   this.props.setError(err.response.data.description)               } else {                   this.setState({                       error: err.response.data.description,                   })               }           })   } } export default SpecificErrorRequest 

, , , x . , , . , , — , , , . , , . , , , — .

▍,


, , , . , , - . .


,

SpecificErrorFrontend.js , .

 import React, { Component } from 'react' import axios from 'axios' import InlineError from './InlineError' class SpecificErrorRequest extends Component {   constructor(props) {       super(props)       this.state = {           error: '',           city: '',       }       this._callBackend = this._callBackend.bind(this)       this._changeCity = this._changeCity.bind(this)   }   render() {       return (           <div>               <input                   type="text"                   value={this.state.city}                   style={{ marginRight: 15 }}                   onChange={this._changeCity}               />               <button onClick={this._callBackend}>Delete your city</button>               <InlineError error={this.state.error} />           </div>       )   }   _changeCity(e) {       this.setState({           error: '',           city: e.target.value,       })   }   _validate() {       if (!this.state.city.length) throw new Error('Please provide a city name.')   }   _callBackend() {       this.setState({           error: '',       })       try {           this._validate()       } catch (err) {           return this.setState({ error: err.message })       }       axios           .delete('/api/city')           .then(result => {               //  -     ,               })           .catch(err => {               if (err.response.data.error === 'GENERIC') {                   this.props.setError(err.response.data.description)               } else {                   this.setState({                       error: err.response.data.description,                   })               }           })   } } export default SpecificErrorRequest 

▍


, , ( GENERIC ), , . , , , , , , , , . .

たずめ


Webアプリケヌションで゚ラヌを凊理する方法を理解しおいただけたこずを願っおいたす。このようなものconsole.error(err)は、デバッグ目的でのみ䜿甚する必芁がありたす。プログラマヌが忘れたものは、本番環境に䟵入しないでください。loglevelのような適切なラむブラリを䜿甚しお、ロギングの問題の解決を簡玠化したす。

芪愛なる読者 プロゞェクトの゚ラヌをどのように凊理したすか

Source: https://habr.com/ru/post/J431078/


All Articles