阿里面试
(2018-09)xxxxxx
-
hsf原理
-
nextTick、setImmediate
setImmediate是在事件队列以后 nextTick在每次事件队列之前,在当前进程执行完以后立即执行
-
koa-middleware中调两次next()
if (i <= index) return Promise.reject(new Error('next() called multiple times')) -
node程序sleep三秒
console.log('begin') sleep(3); function sleep(seconds) { const begin = new Date() const waitTill = new Date(begin.getTime() + seconds * 1000) while(waitTill > new Date()) {} console.log('how long ', new Date() - begin) } -
浏览器从输入网址到渲染的整个过程
- DNS 查询
- TCP 连接
- HTTP 请求即响应
- 服务器响应
- 客户端渲染
这五个步骤并不一定一次性顺序完成。如果 DOM 或 CSSOM 被修改,以上过程需要重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染
-
处理 HTML 标记并构建 DOM 树。
-
处理 CSS 标记并构建 CSSOM 树。
-
将 DOM 与 CSSOM 合并成一个渲染树。
-
根据渲染树来布局,以计算每个节点的几何信息。
-
将各个节点绘制到屏幕上。 1.默认情况下,CSS被视为阻塞渲染饿资源,这意味着浏览器将不会渲染任何已处理的内容,直至CSS-DOM构建完毕 2.JS不仅可以读取和修改DOM属性,还可以读取和修改CSS-DOM属性
存在阻塞的CSS资源时,浏览器会延迟JS的执行和DOM构建,并且: - 当浏览器遇到一个script标签时,DOM将构建暂停,直至脚本执行结束 - CSS-DOM构建时,JS将暂停执行,直至CSS-DOM就绪
实际使用时,应遵循以下两个原则 1.CSS优先:引入顺序上,CSS资源先于JS资源 2.JS应尽量少影响DOM的构建
-
改变CSS的阻塞模式
- 设置media
- 提供媒体查询
-
改变JS阻塞模式 defer & async 在inline-script皆无效
- defer 使用延迟加载的方式 defer属性表示延迟执行引入的JS,即和HTML的构建是并行的
- async 表示异步执行引入 如果已经加载好,就会开始执行,执行顺序不一致
-
document.createElement 默认加载的JS是异步的document.createElement("script").async --> (default: true) 创建link标签已知在chrome中不会阻塞渲染
-
-
如何在node中捕获异常不让程序崩溃
-
同步方法 使用return
const divideSync = (x, y) => { // if error condition? if (y === 0) { // "throw" the error safely by returning it return new Error("Can't divide by zero") } else { // no error occured, continue on return x / y } } // Divide 4/2 let result = divideSync(4, 2) // did an error occur? if (result instanceof Error) { // handle the error safely console.log('4/2=err', result) } else { // no error occured, continue on console.log('4/2=' + result) } // Divide 4/0 result = divideSync(4, 0) // did an error occur? if (result instanceof Error) { // handle the error safely console.log('4/0=err', result) } else { // no error occured, continue on console.log('4/0=' + result) } -
基本的回调函数 return 出error。error为null时程序正常
const divide = (x, y, next) => { // if error condition? if (y === 0) { // "throw" the error safely by calling the completion callback // with the first argument being the error next(new Error("Can't divide by zero")) } else { // no error occured, continue on next(null, x / y) } } divide(4, 2, (err, result) => { // did an error occur? if (err) { // handle the error safely console.log('4/2=err', err) } else { // no error occured, continue on console.log('4/2=' + result) } }) divide(4, 0, (err, result) => { // did an error occur? if (err) { // handle the error safely console.log('4/0=err', err) } else { // no error occured, continue on console.log('4/0=' + result) } }) -
基于事件流
手动触发一个error事件
// Definite our Divider Event Emitter const events = require('events') const Divider = function() { events.EventEmitter.call(this) } require('util').inherits(Divider, events.EventEmitter) // Add the divide Divider.prototype.divide = function(x, y) { // if error condition? if (y === 0) { // "throw" the error safely by emitting it const err = new Error("Can't divide by zero") this.emit('error', err) } else { // no error occured, continue on this.emit('divided', x, y, x / y) } // Chain return this; } // Create our divider and listen for errors const divider = new Divider() divider.on('error', (err) => { // handle the error safely console.log(err) }) divider.on('divided', (x, y, result) => { console.log(x + '/' + y + '=' + result) }) // Divide divider.divide(4, 2).divide(4, 0) -
安全地捕获异常
- domain包含代码块
var d = require('domain').create() d.on('error', function(err){ // handle the error safely console.log(err) }) // catch the uncaught errors in this asynchronous or synchronous code block d.run(function(){ // the asynchronous or synchronous code that we want to catch thrown errors on var err = new Error('example') throw err })- 如果知道可能发生错误的地方,并且无法使用domain时(*异步无法被try catch捕获)
// catch the uncaught errors in this synchronous code block // try catch statements only work on synchronous code try { // the synchronous code that we want to catch thrown errors on var err = new Error('example') throw err } catch (err) { // handle the error safely console.log(err) }- 使用try包含你的异步回调函数
var divide = function (x, y, next) { // if error condition? if (y === 0) { // "throw" the error safely by calling the completion callback // with the first argument being the error next(new Error("Can't divide by zero")) } else { // no error occured, continue on next(null, x / y) } } var continueElsewhere = function (err, result) { throw new Error('elsewhere has failed') } try { divide(4, 2, continueElsewhere) // ^ the execution of divide, and the execution of // continueElsewhere will be inside the try statement } catch (err) { console.log(err.stack) // ^ will output the "unexpected" result of: elsewhere has failed } -
使用process.on('uncaughtException')捕获
// catch the uncaught errors that weren't wrapped in a domain or try catch statement // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound process.on('uncaughtException', function(err) { // handle the error safely console.log(err) }) // the asynchronous or synchronous code that emits the otherwise uncaught error var err = new Error('example') throw err
-
-
try catch是否能捕获异步的异常在node中 不能,需要进行回调处理
-
websocket的鉴权
-
使用一个ticket
-
在connection时检查remoteAddress的cookie信息
-
如果不通过,则terminate
-
把ticket主动发送给客户端,让其保存
-
每次onMessage检查ticket、时效、token
源码服务器端JavaScript
import url from 'url' import WebSocket from 'ws' import debug from 'debug' import moment from 'moment' import { Ticket } from '../models' const debugInfo = debug('server:global') // server 可以是 http server实例 const wss = new WebSocket.Server({ server }) wss.on('connection', async(ws) => { const location = url.parse(ws.upgradeReq.url, true) const cookie = ws.upgradeReq.cookie debugInfo('ws request from: ', location, 'cookies:', cookie) // issue & send ticket to the peer if (!checkIdentity(ws)) { terminate(ws) } else { const ticket = issueTicket(ws) await ticket.save() ws.send(ticket.pojo()) ws.on('message', (message) => { if (!checkTicket(ws, message)) { terminate(ws) } debugInfo('received: %s', message) }) } }) function issueTicket(ws) { const uniqueId = ws.upgradeReq.connection.remoteAddress return new Ticket(uniqueId) } async function checkTicket(ws, message) { const uniqueId = ws.upgradeReq.connection.remoteAddress const record = await Ticket.get(uniqueId) const token = message.token return record && record.expires && record.token && record.token === token && moment(record.expires) >= moment() } // 身份检查,可填入具体检查逻辑 function checkIdentity(ws) { return true } function terminate(ws) { ws.send('BYE!') ws.close() } ticket import shortid from 'shortid' import { utils } from '../components' import { db } from './database' export default class Ticket { constructor(uniqueId, expiresMinutes = 30) { const now = new Date() this.unique_id = uniqueId this.token = Ticket.generateToken(uniqueId, now) this.created = now this.expires = moment(now).add(expiresMinutes, 'minute') } pojo() { return { ...this } } async save() { return await db.from('tickets').insert(this.pojo()).returning('id') } static async get(uniqueId) { const result = await db .from('tickets') .select('id', 'unique_id', 'token', 'expires', 'created') .where('unique_id', uniqueId) const tickets = JSON.parse(JSON.stringify(result[0])) return tickets } static generateToken(uniqueId, now) { const part1 = uniqueId const part2 = now.getTime().toString() const part3 = shortid.generate() return utils.sha1(`${part1}:${part2}:${part3}`) } } utils import crypto from 'crypto' export default { sha1(str) { const shaAlog = crypto.createHash('sha1') shaAlog.update(str) return shaAlog.digest('hex') }, }
-
-
会话劫持
-
敏捷开发
-
spring boot注解原理
-
tree shaking
-
死锁(哲学家问题)
-
MB字节
-
handle Promise Error
-
Bridge
-
redux中间件
-
https加密步骤
-
开发组件库怎么减少代码的量
-
PureComponent
-
笔试题
// 1. 写一个函数实现数字格式化输出,比如输入 00999999999,输出为 999,999,999
const filter = (str, replace = ',') => { const arr = str.split(''); return arr.reduce((init, item, index) => { if (index !== 0 && index%3 === 0) { init += replace; } if (!!parseInt(item, 10)) { init += item; } return init; }, ''); }// 2. 编写一个函数 parse queryString,它的用途是把 URL 参数解析为一个key, value对象
const convert = (url, replace = '=') => { // localhost:8081/api/test?name=asdasd&b=adasd const index = url.indexOf('?') const shortUrl = url.slice(index + 1) const arr = shortUrl.split('&') return arr.reduce((init, item) => { const keys = item.split(replace); init[keys[0]] = keys[1] return init; }, {}) }// 3. 有一段文本它的内容是:var text=“内容文字…”,文本中包含部分敏感词汇,如[“萨德”,“中共”]。 // 请编写函数查找到这些敏感词,并将其字体颜色更改为红色
const change = (text, filters = [ '萨德', '中共']) => { const regStr = filters.reduce((init, item) => { init +=`(${item})|` }, ''); const reg = new Reg(`/${regStr.slice(0, regStr.length - 1)}/g`); return text.replace(reg, `<span style="color: red">$&1<span>`); }
nodeJs事件机制
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
- 技术团队的结构、他们使用了哪些技术、用到了哪些工具,遇到了哪些挑战,以及他们的系统架构
- 你们最近遇到了什么技术挑战?
- 你在这个公司最满意的一点是什么?
- 你们的团队是怎样的结构,工作是怎么分配的?
- timers 这个阶段执行由setTimeout和setInterval发出的回调
- pending callbacks 执行延期到下一个事件循环的I/O callbacks
- idle, prepare 内部使用
- poll 恢复新的I/O事件,执行几乎除了timers、setImmediate、close callbacks
- check setImmediate在这里触发
- close callbacks 一些关闭事件的回调(socket.on('close', ...))