我们先假设一个需求,模拟异步请求(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是不能从失败变成成功的,也不能从成功变成失败的,这句话很重要的感觉!
我们先用原生的promise来演示,之前写的简易版的promise是没有这个普通值处理的。学习这个主要就是了解promise对普通值的处理,顺便将上面的代码优化一下。
如果成功或则失败的回调返回的是普通值(不是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的。
这里是会有不太懂的地方,四种不同的情况。这里要区分一下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 没有错误处理(没有写错误处理) 会向下找
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))