Node-Interview-QA

前言:简要翻译 RisingStack 上关于 Node.js 的面试题,包括 2015 年和 2017年

2015 年 RisingStack Node.js 面试题

2017 年 RisingStack Node.js 面试题

1. What is an error-first callback? 什么是错误优先回调?

在异步编程的回调函数中,第一个参数一般是传递 error 对象,用于检查程序是否运行正常。正常时,error 对象为 null 。例如 fs.readFile

1
2
3
4
5
6
7
fs.readFile('./test.js', function (err, data) {
if (err) {
// something went wrong
} else {
// handle the data
}
})

为什么在回调函数中,第一个参数是 error 对象呢?
这是一种约定,是 node 设计的原则,当执行回调时,检测程序是否报错,如果存在,则优先处理错误信息,反之继续执行。

2. How can you avoid callback hells? 怎样避免回调地狱?

  • 利用 Promise,ES6 已原生支持 Promise 对象
  • ES6 的 Generator
  • ES7 提出的 async/await (未标准化)
  • 使用 koa (底层使用的还是 async/await )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve('result')
    }, 100)
    })
    .then(console.log)
    .catch(console.error)
    async function handleData () {
    let data = await getData() // 异步获取数据的方法
    }

3. How can you listen on port 80 with Node? 如何让 Node 监听 80 端口?

Node 程序其实不应该监听 80 端口,需要超级管理员权限,同时这也不是一个好的实践。如果实在是要让程序监听 80 端口,应该使用 Ngnix 一类的反向代理服务器去代理 80 端口
HTTP 默认端口是 80,HTTPS默认端口是 443

4. What’s the event loop? 什么是事件循环?

Node 支持多线程(通过 libuv ),但是只能运行在单线程环境
每一次 I/O 都会有一个回调函数。
当进程启动时,Node 会创建类似 while(true) 循环,每一次循环称为 Tick 。每个 Tick 的过程就是查看任务队列中有没有事件,有则取出事件及相关回调,并执行回调。接着进入下一个 Tick。

5. What tools can be used to assure consistent style? 哪些工具可以让项目代码风格保持一致?

ESLint

6. What’s the difference between operational and programmer errors? 运行错误与编码错误有什么区别?

运行错误并不算是 bug,可能是由于系统的一些故障导致的;而编码错误是真正的 bug。

7. Why npm shrinkwrap is useful? 为啥 NPM shrinkwrap很有用?

当开发 Node 应用时,使用 shrinkwrap 可以锁定依赖包的版本。目前推荐使用 yarn ,默认提供了 lock 功能,只要不执行 yarn upgrade,删除后再重新安装模块的版本不会发生变化。

8. What’s a stub? Name a use case. 什么是 stub? 举个栗子

Stub 是用于模拟组件/模块的行为的函数或程序。Stub 在测试用例期间进行模拟的函数调用,并返回虚构的结果。

1
2
3
4
5
6
7
8
var fs = require('fs')
var readFileStub = sinon.stub(fs, 'readFile', function (path, cb) {
return cb(null, 'filecontent')
})
expect(readFileStub).to.be.called
readFileStub.restore()

9. What’s a test pyramid? How can you implement it when talking about HTTP APIs? 什么是测试金字塔?当涉及到 HTTP APIs 时,要如何实现它?

测试金字塔,指的是编写测试用例时,底层的单元测试要比上层端到端的单元测试多得多。
当涉及到 HTTP APIs 时,总结如下

  • 很多针对模型的底层单元测试
  • 当测试模型如何交互时,应减少集成测试
  • 当测试实际的 HTTP 端时,减少验收测试

10. What’s your favourite HTTP framework and why?

无标准答案,自由发挥。目前推荐讲述下 koa 的优缺点,以及与 Express 的对比

11. When are background/worker processes useful? How can you handle worker tasks? 后台进程什么时候有用?你是如何处理后台任务?

当需要在后台进行数据处理时,例如发送电子邮件或处理图像,后台进程很有用。
处理耗时的后台任务时,可以通过创建子进程,或者使用一些消息队列,如 RabbitMQ

12. How can you secure your HTTP cookies against XSS attacks? 如何防止 HTTP 的cookies 被 XSS攻击?

设置 HTTP 头部 set-cookie 的属性 HttpOnly 或者 secure

1
Set-Cookie: name=value; secure; HttpOnly

13. How can you make sure your dependencies are safe? 如何确保引用的依赖包是安全的?

自动执行依赖关系的更新或者对引入的依赖进行安全审查

  • Trace by RisingStack
  • NSP
  • GreenKeeper
  • Snyk

Node.js 答疑解惑

错误代码片段

1
2
3
new Promise((resolve, reject) => {
throw new Error('error')
}).then(console.log)

没有 catch ,无法捕获异常
更正如下:

1
2
3
4
5
6
7
8
new Promise((resolve, reject) => {
throw new Error('error')
}).then(console.log).catch(console.error)
// 当你不知道哪个 promise 可能会隐藏问题时,使用 unhandledRejection ,可以打印出所有未处理的 Promise reject
process.on('unhandledRejection', (err) => {
console.log(err)
})

错误代码片段

1
2
3
4
5
6
function checkApiKey (apiKeyFromDb, apiKeyReceived) {
if (apiKeyFromDb === apiKeyReceived) {
return true
}
return false
}

当你比较安全凭证时,至关重要的一点是不要泄露任何信息,因此你必须确保在固定时间内对其进行比较。如果你不这样做,你的应用程序将容易受到时间攻击。
使用 cryptiles 模块:

1
2
3
function checkApiKey (apiKeyFromDb, apiKeyReceived) {
return cryptiles.fixedTimeComparison(apiKeyFromDb, apiKeyReceived)
}

以下代码输出结果是什么

1
2
3
4
5
6
7
8
9
Promise.resolve(1)
.then((x) => x + 1) // 得到值 2
.then((x) => { throw new Error('My Error') })
.catch(() => 1) // 错误信息被抛弃,返回一个新的值 1
.then((x) => x + 1) // 得到值 2
.then((x) => console.log(x)) // 打印 2
.catch(console.error) // 没有异常抛出,这一行不执行
// 最后输出 2

坚持原创技术分享,您的支持将鼓励我继续创作!