也就是说,在使用JSX的代码文件里面,即使代码中并没有直接使用React,也一定要导入React,这是因为JSX最终会被转译成依赖于React的表达式。
Node的文件模块是由POSIX标准的文件操作包装而来的。
Node文件模块中的函数既有异步版本又有同步版本,异步版本的最后一个函数经常都是回调函数,并且这个回调函数的第一个参数经常都是一个异常,如果异步操作成功了的话,那么这个异常就将会是null或者undefined。需要指出的是,null和undefined转换为布尔值都是false。
对于同步版本的运行来说,异常是立马被抛出的。所以对于同步版本的运行来说,使用try...catch...来捕获异常是十分有必要的。
下面就同步/异步问题举个例子,这里使用文件系统的unlink函数——删除文件来举个例子:
const fs = require('fs')
fs.unlink('./1.txt', (err) => {
if(err){console.log(err)}
console.log('delete success!')
})
//同步版本
try{
fs.unlinkSync('./1.txt')
}catch(err){
console.log(err)
}
console.log('delete success')
异步操作是不会堵塞后续操作的,正是由于这一点,所以对于异步函数来说,他们执行的顺序和代码的顺序是无关的。也正是由于这一点,造成了对于某些复杂的场景来说,硬要让异步代码模拟出那种情况的话那么将会出现可怕的地狱回调。下面就这种不确定性举个例子:
const fs = require('fs')
fs.rename('./1.txt', './2.txt', (err) => {
if(err){console.error(`rename 1.txt accurs error --> ${err}`)}
console.log('rename successful')
})
fs.stats('./2.txt', (err, stats) => {
if(err){console.error(`find the t0607_3_0 status accues error --> ${err}`)}
console.log(`file status:\t${JSON.stringify(stats)}`)
})
运行上面的那个例子,很可能就会抛出错误提示找不到2.txt文件,这是为什么呢?因为fs.rename()函数并不会阻塞fs.stats()函数,所以很可能在fs.rename()函数还没有执行完的时候,fs.stats文件已经开始执行了,因此抛出错误。毕竟fs.stats()函数所需要的花销会大于fs.rename()函数。对于这种问题,正确的做法那就是把后续操作放在前一操作的回调函数里面,这样带来的问题那就是大量的回调了。嚯嚯嚯。
尽管利用异步函数来描述工作流有点拗口,但是利用异步方式的处理方法在某些场景下具有特别明显的性能提升!值得庆幸的是,ES2015和Node8的Promise,async,await和node中util模块的promiseify方法能够减轻地狱回调的出现。像下面这样:
const { promisify } = require('util')
const fs = require('fs')
const rename_promise = promisify(fs.rename)
const stat_promise = promisify(fs.stat)
rename_promise('./t0607_3_0.js', './t0607_3.js')
.then(() => {
stat_promise('./t0607_3.js')
.then((stats) => {console.log(JSON.stringify(stats))})
.catch((err) => {console.log('stat error')})
})
.catch((err) => {
console.log('rename error')
})
好像还是挺丑的。。。累觉不爱。。
1.fs.Watcher类
由fs.watch()函数所返回的对象就是一个fs.Watcher类所实例化的对象,再多嘴几句fs.watch()函数,他的callback就是返回对象的change事件的处理函数,而不是关于异常处理的函数。WTF。。就fs.Watcher()类实例化的对象而言,它能够发射下面的事件:
- change:(eventType, fileName) => {}
- error:(err) => {}
他所实例化出来的对象具有下面的方法:
- close:关闭对其文件的监视行为
下面就其API举几个例子:
const fs = require('fs')
const fsWatcher = fs.watch(__dirname+'/1.txt', (eventType, fileName) => {
console.log(`EventType: ${eventType}\tFileName: ${fileName}`)
})
fsWatcher.on('error', (err) => {console.log(`Appear error in the watch process: ${err}`)})
fs.appendFile(__dirname+'/1.txt', 'world', (err) => {
if(err){console.error(`Appear error in append file process in line8: ${err}`)}
})
上面代码写得很糙,因为如果fs.watch()是异步函数的话,那么两个异步函数的执行顺序那可是没有担保的。
2.fs.ReadStream类
fs.ReadStream类用来描述一种可读流的行为。可读流是一种抽象的概念。我们在这里不予多加介绍。下面介绍一下这个类所能够发送的事件以及这个类所实例化出来的对象所拥有的事件和属性:
- close事件:当ReadStream在底层所对应的那个文件描述符通过fs.close()所关闭的时候会发射这个事件。
- open事件:当ReadStream在底层所对应的那个文件被打开了的时候会发射这个事件。事件处理函数接收一个整形参数表示文件描述符。(fd:integer)=>{}
- readstream.bytesRead:这个属性表示的是这个到目前为止所读的字节数。
- readstream.path:所读文件的路径,返回的这个路径是由fs.createReadStream(path)函数的第一个参数所显式指明的,如果这个参数是字符串的话,那么返回的路径也以字符串的形式返回;如果这个参数是Buffer类型的话,那么返回的这个路径也将以Buffer的形式返回。
3.fs.Stats类
这个类型的对象会由下列的函数返回:fs.stat,fs.lstat,fs.fstat以及他们各自的异步版本。这个数据类型所实例化出来的对象具有下列的方法:
- stats.isFile():判断是否是文件
- stats.isDirectory():判断是否是文件夹
- stats.isBlockDevice():判断是否为块设备,比如说磁盘
- stats.isCharacterDevice():判断是否为字符设备,比如说键盘,打印机
- stats.isSymbolicLink():判断是否为软链接
- stats.isFIFO():判断是否为FIFO设备
- stats.isSocket():判断是否为Socket