try-catch-finally执行以及他们在有return的情况下,基本数据类型、对象以及有异步赋值情况异同分析

这两天面试,遇到好几个人,都是那种我感觉我肚子里的墨水都吐出来完了,难不倒人家,于是问了下家里那位老狗,从最开始就念叨着你问他try-catch在有return的情况下怎么执行的,执行结果是啥,我前面没理,后面确实有点遭不住了,来看看吧,肚子里添点墨水,别把脸丢大了~

做了几个测试:

一、数据执行顺序以及返回结果

原始:try-catch-finally 方法正确书写

created() {
    console.log('outer')
    console.log(this.tryCatch())
  },
  methods: {
    tryCatch() {
      let a = 1
      try {
        console.log('===try inner')
        a = 3
        console.log('try 2')
      } catch {
        console.log('=====catch inner')
      } finally {
        console.log('======finally inner')
        console.log('===finally 2')
        console.log(a)
      }
    }
  },

在这里插入图片描述

运行没毛病。
然后开始变种了,加上 return 会怎么样呢?:

// 1. 在 finally 当中加 return
finally {
	console.log('======finally inner')
     a = 4
     console.log('===finally 2')
     return a
}

在这里插入图片描述
其他不变,只是 finally return 的结果被返回回去了。

再来在 try 中直接返回就返回 a 的值,而 finally 不改变呢?

try {
	a = 3
	return a
} ... finally {
	console.log('======finally inner')
	console.log('===finally 2')
}

在这里插入图片描述
有趣的是,try 中赋了值的 a 的值被返回了,同时 finally 的语句也执行了。

那么,同时在 try finally 中都返回值,最后会获得什么呢?

try {
	a = 3
	return 3
} ... finally {
	console.log('======finally inner')
	a = 4
	console.log('===finally 2')
	reteurn 4
}

在这里插入图片描述
结果显而易见,以 finally 返回的值为准了。

这,我就有点兴奋了,要是有一个是异步呢?
不慌,先看看 catch,保留 try 中的返回值,我在 try 中故意写错语句,让其进入 catch 中去,:

try {
	a = 3
	a.b = 'test'
	return a
} catch {
	console.log('=====catch inner')
	console.log(a)
} finally {
	console.log('======finally inner')
	console.log(a)
    a = 4
    console.log('===finally 2')
    return a
}

运行结果还是 4,且 try 中错误之前的语句都执行了的:
在这里插入图片描述
那么我在 catch 当中赋值呢?

...catch{
	console.log('=====catch inner')
    console.log(a)
    a = 10
} finally {
	console.log('======finally inner')
    console.log(a)
    a = 4
    console.log('===finally 2')
    return a
}

catch中赋值结果
仍然是4,但是传入给 finallya 的值是 catch 中赋的值!如果在 catch 当中 return a 也是一样的,会进入到 finally 中去,那如果 finally 不返回值呢?

实验两种情况:
一种是 try 中无错,但 try catch 中都有返回值:

try {
	console.log('===try inner')
	a = 3
	return a
    console.log('try 2')
} catch {
	console.log('=====catch inner')
    console.log(a)
    a = 10
    return a
} finally {
	console.log('======finally inner')
    console.log(a)
    a = 4
    console.log('===finally 2')
}

这种情况下,最终的返回值 a 为3;
第二种情况是 try 中既有返回值,也有错误

try {
	console.log('===try inner')
	a = 3
	a.b = 'test'
	return a
    console.log('try 2')
} catch {
	console.log('=====catch inner')
    console.log(a)
    a = 10
    return a
} finally {
	console.log('======finally inner')
    console.log(a)
    a = 4
    console.log('===finally 2')
}

此种情况下最终返回值为 10

最后,不再在 finally 中加个错误代码都对不起我严谨的工作态度!

...finally{
	console.log('======finally inner')
    console.log(a)
    a = 4
    a.c = '1'
    console.log('===finally 2')
}

结果,报错了…
finally中加入错误数据

由此可看出:try-catch-finally 是顺序执行的,catch 会在 try 出现错误的时候基于 try 中的结果继续运行,最终数据流入到 finally 中,而 finally ,如果没有返回值,那就找它之前的步骤的 返回值 返回,每一个 过程 都有一个独立的隔离域(命名空间),数值在其中的赋值等操作是生效的,但如果在那一步不返回,则最终返回值的计算结果以有返回值那个为准。
另外,finally 中如果出现错误,是不会再次进入 catch 中的,直接报错拉!

得了,搞半天,就是个流水线和命名空间的事儿。上一次的执行返回结果会进入到下一流程,如果没有返回结果,则对外来说流程作废,内部流程还是进行了的。

说到这,我还没开始验证异步赋值的情况,又对数据是个对象有点感兴趣了!

二、变量为对象的情况下的返回结果

基于上一步的结论分析,这次只是多定义一个对象,然后 finally 中不 return ,但是会改变对象值,看看最终的结果:

tryCatch() {
      let a = 1
      const obj = {
        try: '',
        catch: '',
        finally: ''
      }
      try {
        console.log('===try inner')
        a = 3
        obj.try = 'try'
        console.log('obj: ', obj)
        return { a, obj }
        console.log('try 2')
      } catch {
        console.log('=====catch inner')
        console.log('a: ', a)
        console.log('obj: ', obj)
        a = 10
        obj.catch = 'catch'
        return { a, obj }
      } finally {
        console.log('======finally inner')
        console.log('a: ', a)
        a = 4
        console.log('a: ', a)
        console.log('obj: ', obj)
        obj.finally = 'finally'
        console.log('obj: ', obj)
        console.log('===finally 2')
      }
    }

try-catch中使用对象赋值再返回的值的情况
结果也跟预想的一样,肯定是遵守语言的特性的。引用类型的对象的属性值数据会被后面的步骤更改(即使不返回)。

tryCatch() {
      let a = 1
      const obj = {
        try: '',
        catch: '',
        finally: ''
      }
      try {
        console.log('===try inner')
        a = 3
        obj.try = 'try'
        a.b = 'test'
        console.log('obj: ', obj)
        return { a, obj }
        console.log('try 2')
      } catch {
        console.log('=====catch inner')
        console.log('a: ', a)
        console.log('obj: ', obj)
        a = 10
        obj.catch = 'catch'
        return { a, obj }
      } finally {
        console.log('======finally inner')
        console.log('a: ', a)
        a = 4
        console.log('a: ', a)
        console.log('obj: ', obj)
        obj.finally = 'finally'
        console.log('obj: ', obj)
        console.log('===finally 2')
      }
    }

此时,对象的值是不影响的(都会被执行)。
在这里插入图片描述
最后剩下异步的问题了…

三、在 try catch finally 中有异步设置数据的情况下,怎么返回呢?

首先我们照样分别定义一个基本类型数值,和引用类型的,再来对比,代码比较多,直接上代码:

created() {
    console.log('outer')
    console.log(this.tryCatch())
  },
  methods: {
    tryCatch() {
      let a = 1
      const obj = {
        try: '',
        catch: '',
        finally: ''
      }
      let promiseValue = 0
      const promiseObj = {
        try: '',
        catch: '',
        finally: ''
      }
      try {
        console.log('===try inner')
        a = 3
        obj.try = 'try'
        console.log('obj: ', obj)
        console.log('promiseValue before: ', promiseValue)
        promiseValue = this.A(promiseValue)
        console.log('promiseValue after: ', promiseValue)
        return { a, obj, promiseValue, promiseObj }
        console.log('try 2')
      } catch {
        console.log('=====catch inner')
        console.log('a: ', a)
        console.log('obj: ', obj)
        a = 10
        obj.catch = 'catch'
        return { a, obj, promiseObj, promiseValue }
      } finally {
        console.log('======finally inner')
        console.log('a: ', a)
        a = 4
        console.log('a: ', a)
        console.log('obj: ', obj)
        obj.finally = 'finally'
        promiseValue = 123
        new Promise((resolve) => {
          console.log('===promise inner')
          promiseObj.finally = 'finally'
          promiseValue = 456
          resolve()
        }).then(() => {
          console.log('promise then')
          promiseObj.finally = 'finally - '
        })
        console.log('obj: ', obj)
        console.log('promiseObj: ', promiseObj)
        console.log('===finally 2')
      }
    },
    async A(a) {
      console.log('====  function A ')
      await new Promise(resolve => setTimeout(resolve, 1000))
      return this.B(a)
    },
    B(a) {
      console.log('=====  function B ')
      a = 111
      return a
    }
  },

运行结果:
try-catch中使用对象和异步的返回结果
由运行结果可以看出,在 try catch finally 中,只影响最终的返回值,其他的遵照语言特性(相当于函数嵌套,有返回值则重新赋值,无返回值则形成作用域隔离,对最终值无影响,只是运行,如果传入参数为引用类型,则值会被更改)。

四、补充一个前端 promise 中使用 try catch finally 的运行结果

由之前的结果联想到前端请求中的运行等是否相同,于是在项目中做了如下测试:

async created() {
    console.log('====created')
    console.log(await this.getTryCatch())
}
methods: {
	getTryCatch() {
      return new Promise((resolve, reject) => {
        console.log('====主')
        resolve('a')
      }).then(res => {
        console.log('=====then1:')
        console.log(res)
        return 'then1 success'
      }).then(res => {
        console.log('====then2:')
        console.log(res)
        return 'then2 success'
      }).catch(err => {
        console.log('===catch:')
        console.log(err)
        return 'catch error'
      }).finally(() => {
        console.log('====finally')
        console.log('=======down===')
        return 'finally success'
      })
    },
}

首先,在 Promise 中,必须用 resolve reject 这个进入下一环节没毛病;
然后按照之前的案例来写 then catch finallythen 我写了两个,用于检测返回值到底怎么返回。
首先,全部都有 return 的情况,运行结果如下:
Promise中使用then,catch,finally有返回值的情况
可见,返回值为最后一个 then 的返回值。跟 try catch 相同,所有的步骤都会执行。

第二步,我们去掉第二个 then 中的 return ,查看返回值:

Promise中then有返回值的情况
结果为 undefined ,所以必须返回最后一个 then 的返回值。

最后一步,去除所有 then 中的返回值,结果如下:
Promise中then无返回值,finally中有返回值
then 中无返回值,但 finally 中有返回值,最后返回的结果为:undefined

catch 同理。

由上得出结论:
Promise 中,只会返回 thencatch 的返回值,finally 中的返回值无效,但会执行每个阶段的代码。

再看修改对象的执行(基本能猜到是一样的):

async created() {
    console.log('====created')
    const obj = {
      then1: '',
      then2: '',
      catch: '',
      finally: ''
    }
    console.log(await this.getTryCatch(obj))
    console.log(obj)
}
methods: {
getTryCatch(obj) {
      return new Promise((resolve, reject) => {
        console.log('====主')
        resolve('a')
      }).then(res => {
        console.log('=====then1:')
        obj.then1 = 'then1'
        console.log(res)
        return 'then1 success'
      }).then(res => {
        console.log('====then2:')
        console.log(res)
        obj.then2 = 'then2'
        // return 'then2 success'
      }).catch(err => {
        console.log('===catch:')
        console.log(err)
        obj.catch = 'catch'
        return 'catch error'
      }).finally(() => {
        console.log('====finally')
        console.log('=======down===')
        obj.finally = 'finally'
        obj.then1 = 'finally then1'
        return 'finally success'
      })
    },
}

最后执行结果:
promise中then,catch,finally修改对象值结果
结果来了,跟 try catch 一样!

下课!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值