| 
 | 1 | +# 异常捕获  | 
 | 2 | + | 
 | 3 | +## ES5  中的传统做法  | 
 | 4 | + | 
 | 5 | +假设代码块执行抛出错误 fail,那么捕获该错误的写法为:  | 
 | 6 | + | 
 | 7 | +```js  | 
 | 8 | +try {  | 
 | 9 | +  // 代码块执行,并抛出 fail 错误  | 
 | 10 | +  throw new Error('fail');  | 
 | 11 | +} catch (e) {  | 
 | 12 | +  console.log(e);  | 
 | 13 | +}  | 
 | 14 | +```  | 
 | 15 | + | 
 | 16 | +### 定时器  | 
 | 17 | + | 
 | 18 | +我们先来针对上面的代码改写一下,加入一个定时器。  | 
 | 19 | + | 
 | 20 | +```js  | 
 | 21 | +try {  | 
 | 22 | +  setTimeout(()=>{  | 
 | 23 | +    throw new Error('fail');  | 
 | 24 | +    // Uncaught Error: fail  | 
 | 25 | + 	}, 1000);  | 
 | 26 | +} catch (e) {  | 
 | 27 | +  console.log(e);  | 
 | 28 | +}  | 
 | 29 | +```  | 
 | 30 | + | 
 | 31 | +像这样,将 try/catch 扔在定时器的外面,是无法捕获到内部的错误的。  | 
 | 32 | + | 
 | 33 | +正确的做法应该是:  | 
 | 34 | + | 
 | 35 | +```js  | 
 | 36 | + setTimeout(()=>{  | 
 | 37 | +  try{  | 
 | 38 | +    throw new Error('fail');  | 
 | 39 | +  } catch (e) {  | 
 | 40 | +    console.log(e);  | 
 | 41 | +  }  | 
 | 42 | +},1000);  | 
 | 43 | +```  | 
 | 44 | + | 
 | 45 | +### Promise  | 
 | 46 | + | 
 | 47 | +```js  | 
 | 48 | +function doSomething() {  | 
 | 49 | +  return new Promise((resolve, reject) => {  | 
 | 50 | +    // 同步代码中的 throw 可以被捕捉到  | 
 | 51 | +    throw new Error('fail');  | 
 | 52 | +  });  | 
 | 53 | +}  | 
 | 54 | + | 
 | 55 | +doSomething()  | 
 | 56 | +  .then((x) => {  | 
 | 57 | +    console.log('success:', x);  | 
 | 58 | +  })  | 
 | 59 | +  .catch((err) => {  | 
 | 60 | +    console.log('fail:', err);  | 
 | 61 | +  });  | 
 | 62 | +```  | 
 | 63 | + | 
 | 64 | +这样写是没有问题的,错误能够被捕获到。但只要稍微修改一下,可能就出现问题了。比如:  | 
 | 65 | + | 
 | 66 | +```js  | 
 | 67 | +function doSomething() {  | 
 | 68 | +  return new Promise((resolve, reject) => {  | 
 | 69 | +    // 异步代码中的 throw 不能被 Promise 的 catch 捕捉到  | 
 | 70 | +    setTimeout(() => {  | 
 | 71 | +      throw new Error("fail");  | 
 | 72 | +    }, 1000);  | 
 | 73 | +  });  | 
 | 74 | +}  | 
 | 75 | + | 
 | 76 | +doSomething()  | 
 | 77 | +  .then((x) => {  | 
 | 78 | +    console.log('success:', x);  | 
 | 79 | +  })  | 
 | 80 | +  .catch((err) => {  | 
 | 81 | +    console.log('fail:', err);  | 
 | 82 | +  });  | 
 | 83 | +```  | 
 | 84 | + | 
 | 85 | +这里抛出但错误将不能被捕获。所以,在 Promise 中,我们一般通过 reject 来抛出错误。  | 
 | 86 | + | 
 | 87 | +```js  | 
 | 88 | +function doSomething(x) {  | 
 | 89 | +  return new Promise((resolve, reject) => reject(x));  | 
 | 90 | +}  | 
 | 91 | + | 
 | 92 | +doSomething('fail').then((x) => {  | 
 | 93 | +  console.log('success:', x);  | 
 | 94 | +}).catch((err) => {  | 
 | 95 | +  console.log('fail:', err);  | 
 | 96 | +});  | 
 | 97 | +// fail: fail  | 
 | 98 | +```  | 
 | 99 | + | 
 | 100 | +另外,还有一个比较有意思的细节,在 catch 之后继续添加 .then 会被继续执行。  | 
 | 101 | + | 
 | 102 | +```js  | 
 | 103 | +function doSomething(x) {  | 
 | 104 | +  return new Promise((resolve, reject) => reject(x));  | 
 | 105 | +}  | 
 | 106 | + | 
 | 107 | +doSomething('fail').then((x) => {  | 
 | 108 | +  console.log('success:', x);  | 
 | 109 | +}).catch((err) => {  | 
 | 110 | +  console.log('fail:', err);  | 
 | 111 | +  // 这里可以写 return 给下面的方法继续执行  | 
 | 112 | +}).then((x) => {  | 
 | 113 | +  console.log('continue:', x);  | 
 | 114 | +});  | 
 | 115 | +// fail: fail  | 
 | 116 | +// continue: undefined  | 
 | 117 | +```  | 
 | 118 | + | 
 | 119 | +### Async/Await  | 
 | 120 | + | 
 | 121 | +本质上来讲, Async/Await 是通过 Promise 实现,所以基本跟上面 Promise 所讲的差不多。  | 
 | 122 | + | 
 | 123 | +可以在 await 方法外嵌套 try/catch,类似这样:  | 
 | 124 | + | 
 | 125 | +```js  | 
 | 126 | +function doSomething(x) {  | 
 | 127 | +  return new Promise((resolve, reject) => reject(x));  | 
 | 128 | +}  | 
 | 129 | + | 
 | 130 | +(async () => {  | 
 | 131 | +  try {  | 
 | 132 | +    const result = await doSomething('fail');  | 
 | 133 | +    console.log('success:', result);  | 
 | 134 | +    // return 返回  | 
 | 135 | +  } catch (err) {  | 
 | 136 | +    console.log('fail:', err);  | 
 | 137 | +    // return 返回  | 
 | 138 | +  }  | 
 | 139 | +})();  | 
 | 140 | +// fail: fail  | 
 | 141 | +```  | 
 | 142 | + | 
 | 143 | +但这里就有一个问题,比如函数需要有返回,那么返回的语句就需要写两次,正常但时候返回结果,错误的时候,返回一个 `throw new Error()` 或者其他的。有一个小的窍门,可以这样写:  | 
 | 144 | + | 
 | 145 | +```js  | 
 | 146 | +function doSomething(x) {  | 
 | 147 | +  return new Promise((resolve, reject) => reject(x));  | 
 | 148 | +}  | 
 | 149 | + | 
 | 150 | +(async () => {  | 
 | 151 | +  const result = await doSomething('fail').catch((err) => {  | 
 | 152 | +    console.log('fail:', err);  | 
 | 153 | +    return 0; // 默认值  | 
 | 154 | +  });  | 
 | 155 | +  console.log('success:', result);  | 
 | 156 | +})();  | 
 | 157 | +// fail: fail  | 
 | 158 | +// success: 0  | 
 | 159 | +```  | 
 | 160 | + | 
 | 161 | +在错误捕获到之后,重新分配一个默认值,让代码继续运行。  | 
0 commit comments