欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Node之为什么回调函数第一个参数是err

程序员文章站 2022-03-20 18:25:08
本文采取层层递进的方式,让读者更容易理解回调函数在讲解回调函数之前,我们先来看一段代码:function fn(){ function fn2(){ function fn3(){ console.log(3) } fn3(); console.log(2) } fn2(); console.log(1)}fn();console.log(4)执行结果是什么?很简单 3 2 1 ....

本文采取层层递进的方式,让读者更容易理解

回调函数

在讲解回调函数之前,我们先来看一段代码:

function fn(){

  function fn2(){

      function fn3(){

        console.log(3)
        
      }
      fn3();
      console.log(2)
  }
  fn2();
  console.log(1)
}

fn();

console.log(4)

执行结果是什么?
很简单 3 2 1 4

因为函数栈结构是这样的:
Node之为什么回调函数第一个参数是err
先执行fn3,fn3弹出栈后执行fn2,fn2执行完弹出栈,然后执行fn,执行完同样地弹出函数栈,最后执行console.log(4),输出3 2 1 4。

现在假设一个场景:

fn3函数内部是有几率会报错的,修改fn3函数代码:

function fn3(){
        if(Math.random() < 0.7){
          throw new Error('fn3 err')
        }else{
          console.log(3)
        }  
        
      }

我们可以用try…catch语句在fn处捕捉异常:

try{
  fn();
}catch(err){
  console.log(err)
}

这时我们发现,已经可以捕捉到异常了,但是只打印出了4,因为fn3报错,导致异常被try…catch块捕捉,fn3后的程序无法正确执行。
Node之为什么回调函数第一个参数是err
接着我们将报错程序改成异步的,fn3的报错程序改成如下:

setTimeout(()=>{ throw new Error("error"); }, 0)

结果try…catch块无法捕捉异常,因为setTimeOut会放在所有同步代码执行完之后才执行,try…catch块只能捕捉同步异常,无法捕捉异步异常。

所以程序仍然存在两个问题:
1. 无法捕捉异步异常
2. fn3抛同步异常时会导致后续程序无法正常运行

这个时候回调函数就派上用场了,他可以将错误返回给父程序处理,同时不影响后续程序运行,即使在异步条件下,也可以正确执行,实现很简单,即在fn函数传入一个callback参数(名称自定义),让可能出错的程序执行callback函数,如下:

function fn(callback){

  function fn2(){

      function fn3(){
        if(Math.random() < 0.7){
          // 场景1: 同步异常
          callback(new Error("error1"));

          // 场景2: 异步异常
          // setTimeout(()=>{ 
          //   callback(new Error("error1"));
          // }, 0)
        
        }else{
          callback(null, 3)
          console.log(3)
        }  

      }
      fn3();
      console.log(2)
  }
  fn2();
  console.log(1)
}
// try{
//   fn();
// }catch(err){
//   console.log(err)
// }

fn(function(err, res) {
  if(err) console.log(err)
  else console.log(res)
})

这样子的话,也就解释了为什么当需要抛出异常的时候,error参数永远是放在callback函数的第一位,因为在这里我们设定了new Error放置在callback的第一个参数,那么就约定俗成的让error定义在第一位了。而当没有异常发生的时候,第一位则传入null表示没有异常发生。

本文地址:https://blog.csdn.net/qq_43538596/article/details/111030499