promise学习2-链式调用,普通值处理

promise学习2-链式调用,普通值处理

  • 1.链式调用
  • 2.普通值的处理
    • 2.1 回调返回值是普通值
    • 2.2 回调返回值不是普通值
      • 2.2.1 回调是出错的情况
      • 2.2.2 回调是promise

1.链式调用

我们先假设一个需求,模拟异步请求(node的readFile),先从1.txt中读出下一个要读的文件,再读出该文件的内容

let fs = require('fs');
 fs.readFile('./1.txt', 'utf8', function (err, data) {//这种叫error first 错误第一 异步方法无法通过try,catch捕获异常
 if(err){
 }
 fs.readFile(data, 'utf8', function (err, data) {
    if(err){
    }
    console.log(2,data)
    })
 })

这种写法就看着就很不好,带错误处理;而且一旦层级多了,更不优雅。我们用promise来处理,将读文件抽成一个方法。

function read(filename) {
   return new Promise((resolve, reject) => {
      fs.readFile(filename, 'utf8', function (err, data) {
         if (err) return reject(err)
         resolve(data)
      })
   })
}
 read('./1.txt').then((data) => {
   read(data).then((data) => {
      console.log(data)
    }, (err) => {
     console.log(err)
   })
 }, (err) => {
   console.log(err)
 })

这样看着也没有好到哪里去哈,层级多了的话也是不优雅的。其实应该说每次执行完promise.then方法后返回的都是一个"新的promise",因为promise是不能从失败变成成功的,也不能从成功变成失败的,这句话很重要的感觉!

2.普通值的处理

我们先用原生的promise来演示,之前写的简易版的promise是没有这个普通值处理的。学习这个主要就是了解promise对普通值的处理,顺便将上面的代码优化一下。

2.1 回调返回值是普通值

如果成功或则失败的回调返回的是普通值(不是promise类型的值)的话;这之中包括了不return 返回值,不return 返回值其实就相当于return了一个undefined,这个值会传递到下一个then的成功回调中去,不会传到失败的回调中去

//成功 没有return
read('./1.txt').then((data) => {
    console.log(111)
}, (err) => {
   console.log(222)
}).then((data) => {
   console.log(111,data)
}, err => console.log(222,err)) 
// 111 
//111 undefined

//失败 没有return
read('./3.txt').then((data) => {
    console.log(111)
}, (err) => {
   console.log(222)
}).then((data) => {
   console.log(111,data)
}, err => console.log(222,err)) 
//222 
//111 undefined

//成功 有返回值
read('./1.txt').then((data) => {
    return 100
}, (err) => {
   return 200
}).then((data) => {
   console.log(111,data)
}, err => console.log(222,err))
//111 100

//成功 有返回值
read('./1.txt').then((data) => {
    return 100
}, (err) => {
   return 200
}).then((data) => {
   console.log(111,data)
}, err => console.log(222,err))
//111 100

//失败 有返回值
read('./3.txt').then((data) => {
    return 100
}, (err) => {
   return 200
}).then((data) => {
   console.log(111,data)
}, err => console.log(222,err))
//111 200

这里我是有点疑惑的,为什么它能一直往下传呢。记住,每次执行完promise.then方法后返回的都是一个"新的promise",因为promise是不能从失败变成成功的,也不能从成功变成失败的。我们再把代码加一个then

//成功 有返回值
read('./1.txt').then((data) => {
    return 100
}, (err) => {
   return 200
}).then((data) => {
   console.log(111,data)
   return 123
}, err => console.log(222,err)).then((data) => {
   console.log(333,data)
 }, err => console.log(444,err))

我们新加了一个then并且在原来的第二个then的成功回调中return123,结果是能多打印出一行333 123的。

2.2 回调返回值不是普通值

2.2.1 回调是出错的情况

这里是会有不太懂的地方,四种不同的情况。这里要区分一下return 和throw,在 then 方法中使用 return 返回一个错误对象时,该 promise 的状态会转变为已解决(resolved)

//成功 回调的返回值是出错
read('./1.txt').then((data) => {
   return new Error('出错了')
}, (err) => {
  throw err
}).then((data) => {
  console.log(111,data)
}, err => console.log(222,err))
//111 Error: 出错了
  //  at c:\Users\admin\Desktop\daily-study\7.7\tempCodeRunnerFile.js:77:11

//失败 回调的返回值是出错
read('./11.txt').then((data) => {
   // throw new Error('出错了')
   return new Error('出错了')
}, (err) => {
  return err
}).then((data) => {
  console.log(111,data)
}, err => console.log(222,err))
//111 [Error: ENOENT: no such file or directory, open 'c:\Users\admin\Desktop\daily-study\11.txt'] {
//  errno: -4058,
//  code: 'ENOENT',
 // syscall: 'open',
//  path: 'c:\\Users\\admin\\Desktop\\daily-study\\11.txt'
//}

可以看到,无论是在上一个promise的成功回调还是失败回调中如果return一个错误的话,都会传递到下一个then的成功回调中的。
但是如果是throw 一个错误的话,在 then 方法中使用 throw 抛出一个错误时,该 promise 的状态会转变为已拒绝(rejected),并直接触发最近的 catch 方法来捕获和处理错误。后续的 then 方法会被跳过,直接跳到最近的 catch 方法。

//失败 回调是抛出错误
read('./11.txt').then((data) => {
   // throw new Error('出错了')
   throw new Error('出错了')
}, (err) => {
   throw err
}).then((data) => {
   console.log(111, data)
}, err => console.log(222, err)).catch(error => {
   console.log(333, error)
});
//222 [Error: ENOENT: no such file or directory, open 'c:\Users\admin\Desktop\daily-study\11.txt'] {
//  errno: -4058,
 // code: 'ENOENT',
 // syscall: 'open',
 // path: 'c:\\Users\\admin\\Desktop\\daily-study\\11.txt'
//}

//成功 回调是抛出错误
read('./1.txt').then((data) => {
   // throw new Error('出错了')
   throw new Error('出错了')
}, (err) => {
   throw err
}).then((data) => {
   console.log(111, data)
}, err => console.log(222, err)).catch(error => {
   console.log(333, error)
});
//222 Error: 出错了
  //  at c:\Users\admin\Desktop\daily-study\7.7\tempCodeRunnerFile.js:77:10

上面都是throw,之所以没有被catch所触发,是因为被接下来的then的第二个参数有限处理了(可能不太准确)。

//成功 回调的返回值是出错
read('./1.txt').then((data) => {
   // throw new Error('出错了')
   throw new Error('出错了')
}, (err) => {
   throw err
}).then().then((data) => {
   console.log(111, data)
}, err => console.log(222, err))

错误处理 如果离自己最近的then 没有错误处理(没有写错误处理) 会向下找

2.2.2 回调是promise

promise的情况(会根据promise返回的状态,决定下一次的成功还是失败)

read('./1.txt').then((data) => {
   console.log(data)
   return read(data)
},err =>{
).then((data) => {
   console.log(111, data)
}, err => console.log(222, err))
//./2.txt
//111 18

我这是都是成功状态的,所以打印出来的是111 18
最后,我们把最先的代码优化成

read('./1.txt').then((data) => {
   return read(data)
}).then((data) => {
   console.log(111, data)
}, err => console.log(222, err))

你可能感兴趣的:(学习,javascript,前端)