场景导入:
采用es6语法的nodejs进行读取文件的操作:
const fs = require('fs')
const psth = require('path')
function getFileContent (fpath) {
fs.readFile( fpath, 'utf-8', (err, dataStr) => {
if (err) throw err
return dataStr
}
//此时调用调用这个读取文件的函数进行文件的读取操作
var result = getFileContent(path.join(__dirname, './files/01.txt')
此时我们在调用getFileContent函数的时候,并不能够通过函数的执行拿到文件读取出的结果,原因是readFile读取文件是异步的,当函数在进行到此处时,主线程并不去继续执行读取文件的操作,直接就从函数中返回了,而读取文件的操作则是从主线程上分出一个线程去执行,那么,我们在调用函数的时候,就无法通过rerurn的形式拿到读取文件的返回值,此时,要拿到读取文件的内容,只能够通过回调函数的形式去拿取,如下:
const fs = require('fs')
const psth = require('path')
function getFileContent (fpath, callback) {
fs.readFile( fpath, 'utf-8', (err, dataStr) => {
if (err) throw err
callback(dataStr)
}
//此时调用调用这个读取文件的函数进行文件的读取操作
getFileContent(path.join(__dirname, './files/01.txt', (dataStr) => {
console.log(dataStr)
})
此时,我们便可以在回调函数中打印出文件读取的值了,但是,在文件读取的函数中,我们只是将成功读取的信息返回了,在读取文件出错的我们并没有拿到出错信息,只是简单的抛出了这个错误,而要拿到这个信息,我们还得为函数传入一个错误处理的回调函数,或者在一个回调函数中跟据参数的的位置处理或者执行成功或者失败的代码,这显然不是我们想要的;
——————————————————
场景二:
如果我们有这样的需求,在调用完函数读取文件一后,又要调用函数取读取文件二,继续又要读取文件三,那么,此时我们就需要在一次调用中再次回调该函数,如下所示:
const fs = require('fs')
const psth = require('path')
function getFileContent (fpath, callback) {
fs.readFile( fpath, 'utf-8', (err, dataStr) => {
if (err) throw err
callback(dataStr)
}
//此时调用调用这个读取文件的函数进行文件的读取操作
getFileContent(path.join(__dirname, './files/01.txt', (dataStr) => {
console.log(dataStr)
getFileContent(path.join(__dirname, './files/02.txt', (dataStr) => {
console.log(dataStr)
getFileContent(path.join(__dirname, './files/01.txt', (dataStr) => {
console.log(dataStr)
})
})
})
此时,我们就进入了回调地狱中去了,太多的缩进和繁复的括符,那么此时Promise的出现,就可以解决这种回调地狱的问题(此处声明:Promise主要是为了解决回调地狱的问题,并不一定能够简化我们的代码量)
————
我们在浏览器中打印出Promise这个对象来:
由图我们可以知道,Promise其实是一个构造函数,那么既然是构造函数,那么,我们便可以同new一个实例的方式得到一个Promise的实例对象,而对象上存在两个方法,resolve和reject,便是Promise在处理函数成功时的回调和失败时的回调,而Promise的prototype上有一个.then的方法,能够在我们实例Promise后预先为这个Promise传递这两个函数:resolve()和reject(),而由于.then()方法是存在于prototype上的,所以我们可以在Promise的实例上直接点出这个方法。
const fs = require('fs')
const psth = require('path')
new Promise(function() {
fs.readFile( path.join(__dirname, './files/02.txt'), 'utf-8', (err, dataStr) => {
if (err) throw err
console.log(dataStr)
}
})
对于Promise而言,它本身是一个异步的操作,所以,我们通过Promise的实例去执行的函数,并不能够通过return 的形式去得到它的执行结果,只能够通过回调函数的形式将成功或者失败的结果返回给操作者,而此时,我们可以在new出来的这个Promise实例上通过.then()方法给Promise传递这两个回调函数。而由于new出的Promise实例后按照js的执行顺序,直接就会去执行Promise中的函数,那么,此时我们可以通过一个变量的形式去直接拿到这个Promise对象,这样,在它去执行内部函数的操作之前,我们就能够通过.then()方法将其回调函数传递给它:
const fs = require('fs')
const psth = require('path')
function getFlileContent (fpath) {
promise = new Promise(function(resoleve, reject) {
fs.readFile( fpath, 'utf-8', (err, dataStr) => {
if (err) reject(err)
resolve(dataStr)
}
})
return promise
}
getFlileContent(path.join(__dirname, './files/02.txt')).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
}, (err) => {
console.log('读取文件失败:+ err)
})
此时,我们就已经通过Promise的方式读取出了文件中的值,通过.then的方式将Promise的回调函数传递给了Promise实例对象,从而得到了异步操作中的数据值。在为Promise的实例对象传递回调函数时,resolve函数是必传参数,reject函数可以不传。此时,如果我们需要连续读取文件时,也可以就通过Promise.then()方式,规避掉回调地狱的问题:
getFlileContent(path.join(__dirname, './files/01.txt')).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
getFlileContent(path.join(__dirname, './files/02.txt'))
}).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
getFlileContent(path.join(__dirname, './files/03.txt'))
}).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
}).catch(
此时我们就这样代码串联的形式读取完了三个文件中的值,而不是通过不断的回调的代码缩进的形式去读取文件的了。那么,现在有一个问题,就是在Promise的内部函数在出错后,就会立即终止Promise的执行,而抛出错误,那么此时,如果我们想在如上的这种形式中,一个Promise出错,并不会影响到其他Promise的执行,那该怎么搞呢?
——————解决:
如果希望在一个Promise出错后并不会影响到其他Promise的执行,那么,我们需要在Promise的.then方法后继续执行.catch()的方式,此时,当一个Promise执行出错后,会将错误信心抛到catch中去处理,而此时其他的Promise仍然会正常的执行下去:
getFlileContent(path.join(__dirname, './files/01.txt')).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
getFlileContent(path.join(__dirname, './files/02.txt'))
}).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
getFlileContent(path.join(__dirname, './files/03.txt'))
}).then((dataStr) => {
console.log('这是执行成功时的回调:' + dataStr)
}.catch((err) => {
console.log(err.message)
})
至此,关于Promise的基本的用法知识就到这儿了,感谢批评指正!