阿里面試
(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=“內容文字…”,文字中包含部分敏感詞彙,如[“86學潮”,“薩德”,“中共”]。 // 請編寫函式查詢到這些敏感詞,並將其字型顏色更改為紅色
const change = (text, filters = ['86學潮', '薩德', '中共']) => { 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', ...))