【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
函数自调用
一般情况下,把函数作为参数的目的是为了获取函数内部的异步操作结果
-
下方代码是一个同步示例
function add (x + y) { // 函数方法 return x + y } add(10, 20) // 调用函数
-
下方代码是一个异步函数
console.log('setTimeout external before') setTimeout(function () { console.log('setTimeout inside before') console.log('setTimeout inside after') }, 0) console.log('setTimeout external after')
由于
setTimeout
是异步函数,所以在运行时浏览器不会等待(哪怕是执行时间为 0 )函数执行,所以最终输出结果为setTimeout external before setTimeout external after setTimeout inside before setTimeout inside after
之所于得出以上结果,是由于 javascript 是单线程的
-
获取异步函数内部的操作结果
function add (x, y) { setTimeout(function () { var ret = x + y }, 0) }
如何能够获取函数内部
setTimeout
异步函数中ret
的值?首先来看两个错误案例function add (x, y) { setTimeout(function () { var ret = x + y return ret }, 0) } add(10, 20)
运行结果为
Uncaught ReferenceError: ret is not defined
原因在于
setTimeout
中的ret
返回出来的值,在add
函数内部没有变量接收function add (x, y) { var ret setTimeout(function () { ret = x + y }, 0) return ret } add(10, 20)
运行结果为
undefined
原因在于
setTimeout
异步函数的执行顺序为var ret
return ret
最后才是setTimeout
,所以此时结果为undefined
通过回调函数
callback
获得函数内部异步方法的结果function add (x, y, callback) { setTimeout(function () { var ret = x + y callback(ret) }, 0) } add(10, 20, (val) => { console.log(val) })
运行结果为
undefined
30
在代码中调用方法
add()
由三个参数组成,前两个参数传递给异步方法setTimeout
中ret = x + y
用于计算,第三个参数为一个函数,此函数参数为形参,接收ret
最终的运算结果作为实参这样就可以将函数内部的异步方法运行结果抛出对外使用了
CRUD 静态路由搭建
-
首先需要几个静态页面:
index.html
用于展示首页(信息列表)展示页面new.html
用于新增信息页面edit.html
用于对现有信息修改页面需要将静态页面放置于
views
中,以便express
使用 -
创建数据
JSON
文件,命名为db.json
:{ "students": [{ "id": 4, "name":"张三三", "gender":"0", "age":"22" }] }
-
新建项目:
npm init -y // 快速搭建项目
-
创建入口文件
app.js
,引入所需组件及配置// npm install express --save var express = require('express') // 引入 express // npm i art-template app.engine('art', require('express-art-template')) // 配置 express-art-template // npm install --save body-parser var bodyParser = require('body-parser') // 引入 body-parser app.use(bodyParser.urlencoded({ // 配置 body-parser extended: false })) app.use(bodyParser.json())
-
创建路由(为了更好的体现模块化开发,现将路由模块单独提出至
router.js
)14nodejs(7天)
中提供了两种构建方式-
将
app
作为参数传递给router.js
(此方式不推荐)// route.js module.expotrs = (app) => { app.get('/', (req, res) => {}) // 渲染首页 app.get('/new', (req, res) => {}) // 渲染添加信息页面 app.post('/new', (req, res) => {}) // 提交添加的信息 app.get('/edit', (req, res) => {}) // 渲染信息编辑页面 app.post('/edit', (req, res) => {}) // 提交编辑后的信息 app.get('/delete', (req, res) => {}) // 删除信息 } // app.js var express = require('express') // 引入 express var router = require('./route') // 引入 router.js var app = express() router(app) // 将 app 作为参数传递给 router.js
-
使用 Express 包装路由(推荐使用此方式)
// route.js var express = require('express') // 引入 express var router = express.Router() // 使用 express 中 router 方法,创建一个路由容器 // 把路由挂在到 router 上 router.get('/', (req, res) => {}) // 渲染首页 router.get('/new', (req, res) => {}) // 渲染添加信息页面 router.post('/new', (req, res) => {}) // 提交添加的信息 router.get('/edit', (req, res) => {}) // 渲染信息编辑页面 router.post('/edit', (req, res) => {}) // 提交编辑后的信息 router.get('/delete', (req, res) => {}) // 删除信息 module.exports = router // 导出 router 容器 // app.js var express = require('express') // 引入 express var router = require('./route') // 引入 router.js var app = express() app.use(router) // 把路由容器挂在到 app 服务中
-
-
创建
Server
服务app.use('/public/', express.static('./public/')) // 开放 public 目录 app.use(router) // 挂在 router 路由文件 app.listen('2020', () => { // 绑定服务器端口号 console.log('服务器启动成功') })
到此为止,静态文件的跳转就已经到此为止,下面将针对增删改查功能进行逐一的开发
CRUD 增删改查
将所有涉及增删改查的方法,都封装在 student.js
文件中
所有方法通过 exports
导出
最后将 student.js
文件导入 router.js
以便路由使用
方法通过函数自调用将 callback
结果导出
-
增
// student.js var fs = require('fs') // 引入核心组件 fs var dbPath = './db.json' // 引入原始数据文件 exports.add = (student, callback) => { fs.readFile(dbPath, 'utf-8', (err, data) => { if (err) { return callback(err) // 如果 db.json 文件读取失败,则向外抛出 err } var students = JSON.parse(data).students // 将 dbPath 的 JSON 文本数据转换对象 student.id = students[students.length - 1].id + 1 students.push(student) // 将表单数据追加到 students var fileData = JSON.stringify({ // 将对象重新转换为文本 students: students }) fs.writeFile(dbPath, fileData, (err) => { if (err) { // 如果写入文件失败,则向外抛出 err return callback(err) } callback(null) // 写入成功则不作为 }) }) } // router.js var Student = require('./student') // 导入 student.js Student.add(req.body, (err) => {}) // add 方法接收两个参数 // 参数1(Object) 接收 需要添加的数据对象 // 参数2(Function) 该 Function 参数接收 err
-
删
// student.js var fs = require('fs') // 引入核心组件 fs var dbPath = './db.json' // 引入原始数据文件 exports.deleteId = function (id, callback) { fs.readFile(dbPath, 'utf8', function (err, data) { if (err) { return callback(err) // 如果 db.json 文件读取失败,则向外抛出 err } var students = JSON.parse(data).students // 将 dbPath 的 JSON 文本数据转换对象 var deleteId = students.findIndex(function (item) { // findIndex 方法专门用来根据条件查找元素的下标 return item.id === parseInt(id) }) students.splice(deleteId, 1) // 根据下标从数组中删除对应的学生对象 var fileData = JSON.stringify({ // 把对象数据转换为字符串 students: students }) fs.writeFile(dbPath, fileData, function (err) { if (err) { // 如果写入文件失败,则向外抛出 err return callback(err) } callback(null) // 写入成功则不作为 }) }) } // router.js var Student = require('./student') // 导入 student.js Student.deleteId(req.query.id, function (err) {}) // deleteId 方法接收两个参数 // 参数1(String) 接收 用于匹配的数据 id // 参数2(Function) 该 Function 参数接收 err
-
改
// student.js var fs = require('fs') // 引入核心组件 fs var dbPath = './db.json' // 引入原始数据文件 exports.edit = (student, callback) => { fs.readFile(dbPath, 'utf-8', (err, data) => { if (err) { return callback(err) // 如果 db.json 文件读取失败,则向外抛出 err } var students = JSON.parse(data).students // 将 dbPath 的 JSON 文本数据转换对象 var queryId = students.find((item) => { // 通过 req.body.id 找到 dbPath 中匹配的对象 return item.id === parseInt(student.id) }) for (var key in student) { // 替换需修改的对象 queryId[key] = student[key] } var fileData = JSON.stringify({ // 将对象重新转换为文本 students: students }) fs.writeFile(dbPath, fileData, (err) => { if (err) { // 如果写入文件失败,则向外抛出 err return callback(err) } callback(null) // 写入成功则不作为 }) }) } // router.js var Student = require('./student') // 导入 student.js Student.edit(req.body.id, (err) => {}) // edit 方法接收两个参数 // 参数1(String) 接收 用于匹配的数据 id // 参数2(Function) 该 Function 参数接收 err
-
查(所有)
// student.js var fs = require('fs') // 引入核心组件 fs var dbPath = './db.json' // 引入原始数据文件 exports.findAll = (callback) => { fs.readFile(dbPath, 'utf-8', (err, data) => { if (err) { return callback(err) // 如果 db.json 文件读取失败,则向外抛出 err } callback(null, JSON.parse(data).students) // 读取成功则抛出数据 }) } // router.js var Student = require('./student') // 导入 student.js Student.findAll((err, students) => {}) // find 方法接收一个 Function 参数,该 Function 又有两个参数 // 参数1 接收 err // 参数2 接收 真实数据(JSON.parse(data).students)
-
查(单个)
// student.js var fs = require('fs') // 引入核心组件 fs var dbPath = './db.json' // 引入原始数据文件 exports.findId = (queryId, callback) => { fs.readFile(dbPath, 'utf-8', (err, data) => { if (err) { return callback(err) // 如果 db.json 文件读取失败,则向外抛出 err } var students = JSON.parse(data).students // 将 dbPath 的 JSON 文本数据转换对象 var student = students.find((item) => { // 通过 queryId 找到 dbPath 中匹配的对象 return item.id === parseInt(queryId) }) return callback(null, student) }) } // router.js var Student = require('./student') // 导入 student.js Student.findId(req.query.id, (err, data) => {}) // findId 方法接收两个参数 // 参数1(String) 接收 用于匹配的数据 id // 参数2(Function) 该 Function 有两个参数,其一为 err ,其二为真实数据
将方法应用于 router.js
,最终 router.js
页面代码为
var fs = require('fs') // 引入核心组件 fs
var Student = require('./student') // 导入 student.js
var express = require('express') // 导入 express
var router = express.Router() // express 包裹路由
router.get('/', (req, res) => { // 渲染首页
Student.findAll((err, students) => {
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.render('index.html', { // 如果数据读取成功,则渲染首页
students: students
})
})
})
router.get('/new', (req, res) => { // 渲染添加信息页面
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.render('new.html')
})
router.post('/new', (req, res) => { // 提交添加的信息
Student.add(req.body, err => { // 将 req.body 对象添加入 ./db.json
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.redirect('/') // 若添加成功,则页面重定向回首页
})
})
router.get('/edit', (req, res) => { // 渲染信息编辑页面
Student.findId(req.query.id, (err, student) => { // 通过 req.query.id 在 ./db.json 中匹配数据
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.render('edit.html', { // 渲染当前数据的编辑页面
student: student
})
})
})
router.post('/edit', (req, res) => { // 提交编辑后的信息
Student.edit(req.body, (err) => { // 通过 req.body 在 ./db.json 中匹配数据,并将其替换
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.redirect('/') // 若添加成功,则页面重定向回首页
})
})
router.get('/delete', (req, res) => { // 删除信息
Student.deleteId(req.query.id, function (err) { // 通过 req.query.id 在 ./db.json 中匹配数据,并将其删除
if (err) { // 如果 findAll 抛出错误,则报 Server error,状态码 500
return res.status(500).send('Server error.')
}
res.redirect('/') // 若添加成功,则页面重定向回首页
})
})
module.exports = router // 导出 router 容器
文章已同步我的个人博客:《Node学习记录 函数自调用和crud增删改查》
资料参考:
来源:oschina
链接:https://my.oschina.net/sfatpaper/blog/3142237