【騰訊面試題】web開發工程師職位

JavaScript

XMLHttpRequest介紹以及它的readyState狀態碼

XMLHttpRequest 是一個API, 它爲客戶端提供了在客戶端和服務器之間傳輸數據的功能。它提供了一個經過 URL 來獲取數據的簡單方式,而且不會使整個頁面刷新。javascript

readyState屬性, 共有如下5種狀態html

狀態 描述
0 UNSENT 未調用 open()方法
1 OPENED open()已被調用, 未調用send()方法
2 HEADERS RECEIVED send()方法已調用, 響應的狀態和頭部已返回
3 LOADING 加載響應體, responseText中已經獲取了部分數據
4 DONE 整個請求過程已經完畢

如何形容js的閉包

須要提到做用域,做用域分全局做用域和局部做用域,外部變量屬於全局做用域,函數內部變量屬於局部做用域。 函數做用域是定義時肯定的。 內部函數能夠訪問外部函數的變量, 參數, 其它函數聲明。 若是這個內部函數容許在包含的這個函數外被調用,就會造成一個閉包。java

利用閉包生成一個自增id函數node

function createIncId (seed) {
    seed = parseInt(seed) || 0;
   return function () {
        return seed++;
   }
}

var incFn1 = createIncId(100);
var incFn2 = createIncId(10);
incFn1(); // 100
incFn1(); // 101
incFn2(); // 10
incFn2(); // 11

js閉包的內存如何釋放

首先,閉包是因爲執行函數後返回的對象或函數擁有對外部函數的變量,參數和函數聲明具備訪問權。所以,在js的回收機制上,是會被標記這些變量,參數,函數聲明引用(在定義時肯定哪些變量會被添加標記),在定時回收的時候不會考慮將這些佔用的內存回收。若是咱們將返回的對象或函數設置爲null, 那麼就失去了對內部變量的控制,就會被回收。web

下面是一個簡單的例子 在線測試ajax

var createClouse = function () {
    var args = [].slice.call(arguments, 0);
    return {
      // 保存了對 args 的 引用
      getValue: function (index) {
        return args[index] || undefined;
    },
    getIndex: function (val) {
        return args.findIndex(function (arg) {
          return val === arg;
      });
    }
  }
}

var clouse = createClouse({}, [], '', null, undefined, false, 0);

alert(clouse.getIndex(undefined));

// 一旦clouse的引用不存在, 則該對象被標記爲回收狀態
clouse = null;

JavaScript的內存回收機制

採用 Mark-and-sweep(標記掃描)算法算法

  1. 建立"根"列表, 保存引用的全局變量。 在瀏覽器中, window 對象老是存在的, window對象下的對象變量老是存在,因此不會被標記回收。
  2. 從「根」可到達的一切子節點不會被標記回收。
  3. 全部未被標記爲活動的內存塊均可以被標記,交由垃圾回收器進行回收。

JavaScript什麼狀況下會出現內存溢出, 如何防範

要了解如何預防內存泄漏,須要瞭解對象的基本生命週期。對象生命週期, JS爲引用類型分配適當的內存, 從分配的開始起垃圾回收器會不斷對該對象進行評估,檢查是否屬於有效的對象。
垃圾回收器按期掃描對象, 會將引用數量爲0或將對象惟一引用是循環到對象進行回收。chrome

垃圾回收內存

內存泄露方式1: 閉包json

var theThing = null;
  var replaceThing = function () {
    var originalThing = theThing;
    var unused = function () {
      if (originalThing) {
      
        console.log('hi');
      }
    };
    theThing = {
      longStr: new Array(1000000).join('*'),
      someMethod: function () {
        console.log('some message');
      }
    };
    // 顯示標記釋放內存
    // originalThing = null;
  };
  setInterval(replaceThing, 1000);

若是一直執行的話,能夠在chrome工具欄 memory下給 Heap 拍幾張快照,會發現內存會每隔1s鐘不斷增長
圖片描述跨域

緣由在於theThingsomeMethodunused 都爲同一個父做用域, unused 引用了originalThingsomeMethodunsued 共享閉包範圍. 則對originalThing引用強制保持活動狀態防回收.

若是在replaceThing 後面加入 originalThing = null, 則循環後不會使內存增加
圖片描述

內存泄露方式2: 意外的全局變量

function foo () {
    // 意外的綁定在全局 window.bar 變量上
    bar = 'global value';
}
foo();

通常來講,儘可能少用全局變量. 而多用戶函數聲明運行建立一個私有的函數做用域. 局部變量會在執行後進行釋放. 使用 'use strict' 防止出現隱式定義全局變量的狀況

內存泄露方式3: 被遺忘的計時器或回調函數

var someResource = getData();
  var interval = setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
      // Do stuff with node and someResource.
      node.innerHTML = JSON.stringify(someResource));
    } else {
      // clearInterval(interval);
    }
  }, 1000);

一旦node節點不存在, someResource則成爲了避免須要的引用,因爲setInterval定時器仍然存在的關係, 則沒法回收someResource的數據. 解決辦法, 使用clearInterval回收定時器

內存泄露方式4: 脫離 DOM 的引用

var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')
  };
  function doStuff() {
    image.src = 'http://some.url/image';
    button.click();
    console.log(text.innerHTML);
    // Much more logic
  }
  function removeButton() {
    // The button is a direct child of body.
    document.body.removeChild(document.getElementById('button'));
    // At this point, we still have a reference to #button in the global
    // elements dictionary. In other words, the button element is still in
    // memory and cannot be collected by the GC.
  }

DOM的引用在文檔中被刪除,可是在js內還有存在被引用, 則也不會產生垃圾回收。
DOM的節點綁定事件後若是直接刪除DOM,但事件未被刪除,這也會形成泄露。

常見跨域方式有哪些

首先要了解一下同源策略,是瀏覽器核心,基本的安全功能更。限制了一個源中的文本合夥腳本加載來自其餘源的資源.
同源的意思: 同一個協議, 同一個域名, 同一個端口.

跨域方式1: 主域相同兩個子域進行跨域. 設置 document.domain

好比: http://m.liylblog.comhttp://www.liylblog.com
設置 http://m.liylblog.com/a.htmlhttp://m.liylblog.com/b.htmldocument.domainliylblog.com

www.html 腳本

var getDomainIframe = (function (domain, src) {
  document.domain = domain;
  var ifr = document.createElement('iframe');
  ifr.src = src;
  ifr.style.display = 'none';
  document.body.appendChild(ifr);
  var promise = new Promise (function (resolve, reject) {
    ifr.onload = function () {
      ifr.onload = null;
      resolve(ifr.contentWindow);
    };
  });
  return function () {
    return promise;
  }
})('liylblog.com', 'http://m.liylblog.com/public/examples/2017/cros_domain/diff_subdomain/m.html');


function getData (xhr, fn) {
  xhr.open('GET', 'http://m.liylblog.com/public/examples/2017/cros_domain/diff_subdomain/m_data.json', true);
  xhr.onreadystatechange = function () {
    if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
      fn && fn(xhr.responseText);
    }
  }
  xhr.send();
}

document.querySelector('#btn').addEventListener('click', function () {
  getDomainIframe().then(function (win) {
    var xhr = new win.XMLHttpRequest();
    getData(xhr, function (data) {
      document.querySelector('#console').innerHTML = data;
    });
  });
}, false);

m.html 腳本

document.domain = 'liylblog.com';

原理:
獲取到 m.html 的window對象, 則能夠利用這個window對象下的 XMLHttpRequest API對 m.liylblog.com的資源進行ajax請求

在線演示地址

跨域方式2: window.postMessage
HTML5新增的postMessage方法, 能夠實現跨文檔消息傳輸, 經過綁定window.addEventListner('message') 事件來監聽發送文檔消息傳輸內容。

跨域方式3: proxy 服務端代理
將要請求的地址以參數的方式發送給同域的服務器,由服務器代理請求目標地址

跨域方式4: jsonp 動態插入腳本
利用script腳本動態插入並執行的特性, 將請求地址存放至scriptsrc屬性中,當onload加載完畢後執行腳本。

跨域方式5:CORS

跨域資源共享( CORS )機制容許 Web 應用服務器進行跨域訪問控制,從而使跨域數據傳輸得以安全進行。瀏覽器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以下降跨域 HTTP 請求所帶來的風險。
跨域資源共享標準新增了一組 HTTP 首部字段,容許服務器聲明哪些源站有權限訪問哪些資源。
規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法, 進行OPTIONS方法 預檢查請求(preflight request)

重繪(repaint)與迴流(reflow)

重繪
重繪是在一個元素的外觀被改變,但沒有改變佈局的狀況下發生的,如改變了visibility、outline、background等。當repaint發生時,瀏覽器會驗證DOM樹上全部其餘節點的visibility屬性。

迴流
當元素改變的時候,將會影響文檔內容或結構,或元素位置,此過程稱爲 Reflow。

何時會致使迴流發生:

  • 改變窗口大小
  • 改變文字大小
  • 添加/刪除樣式表
  • 內容的改變,(用戶在輸入框中寫入內容也會)
  • 激活僞類,如:hover
  • 操做class屬性
  • 腳本操做DOM
  • 計算offsetWidth和offsetHeight
  • 設置style屬性

PS: 迴流一定引發重繪

setTimeout, setInterval, requestAnimationFrame 區別

setTimeoutsetInterval 主要經過定時任務的方式,執行修改DOM UI的代碼, 從而交給UI線程進行處理渲染. 若是前面有了任務隊列,則執行完前面的任務隊列後再執行動畫任務。

requestAnimationFrame 採用系統時間間隔,保持最佳繪製效率,不會由於間隔時間太短,形成過分繪製,增長開銷;也不會由於間隔時間太長,使用動畫卡頓不流暢,讓各類網頁動畫效果可以有一個統一的刷新機制,從而節省系統資源,提升系統性能,改善視覺效果。

requestAnimationFrame 優勢:

  1. requestAnimationFrame會把每一幀中的全部DOM操做集中起來,在一次重繪或迴流中就完成,而且重繪或迴流的時間間隔牢牢跟隨瀏覽器的刷新頻率
  2. 在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或迴流,這固然就意味着更少的CPU、GPU和內存使用量
  3. requestAnimationFrame 是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,而且若是頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷

HTTP協議

協議介紹

請求過程:
- 請求行 HTTP版本號
- 請求首部 

響應過程:
- 響應HTTP版本號 響應狀態碼 響應狀態
- 響應首部
- 響應實體

HTTP 1.0

每個請求打開一個鏈接,請求結束後會關閉鏈接. 響應的對象本省能夠是任何類型, HTML 文件,文本文件,圖片,其它格式內容。 經過響應頭部Content-Type 指定。

簡單的請求

# telnet website.org 80
> GET /rfc/rfc1945.txt HTTP/1.0
> 兩次回車

HTTP 1.1

相比於HTTP1.0, HTTP1.1多了比較多的性能優化。

  • 持久鏈接
  • 分塊編碼傳輸
  • 字節範圍請求
  • 加強緩存機制
  • 傳輸編碼請求管道

第一次HTTP請求文檔成功後, 還會利用現有的鏈接發送一次請求獲取 favicon.png 網站縮略圖標. 若是任意一方想要停止鏈接,均可以發送 Connection: closed 關閉鏈接。

HTTP 2.0

協議升級方式

ALPN協議(應用層協商協議)
瀏覽器在創建TLS鏈接時,告訴服務器自身支持HTTP1.1HTTP2.0協議. 服務器端獲得信息後,也告訴瀏覽器自身支持HTTP2.0協議。因而將協議轉換成HTTP2.0。接下來經過HTTP2.0進行通訊。

基於HTTP的協商過程

HTTP Upgrade request
GET / HTTP/1.1
host: nghttp2.org
connection: Upgrade, HTTP2-Settings
upgrade: h2c        /*發起帶有HTTP2.0 Upgrade頭部的請求*/       
http2-settings: AAMAAABkAAQAAP__   /*客戶端SETTINGS淨荷*/
user-agent: nghttp2/1.9.0-DEV

HTTP Upgrade response    
HTTP/1.1 101 Switching Protocols   /*服務端贊成升級到HTTP 2.0*/
Connection: Upgrade
Upgrade: h2c

HTTP Upgrade success               /*協商完成*/
幀通訊

緩存方式

HTTP協議的緩存方式 主要分爲強制緩存協商緩存

- Pragma 1.0
- Expires
- Cache-Control

瀏覽器緩存頭部和服務器緩存頭部

網絡

介紹一下 OSI七層模型和 TCP/IP四層模型

OSI七層模型

OSI模型圖

協議層 傳輸方式
物理層 傳輸二進制比特流
數據鏈路層 數據幀 (frame)
網絡層 數據包 (packet)
傳輸層 數據段 (segment)
會話層 管理主機之間的會話進程(socket)
表示層 數據的加密、壓縮、格式轉換
應用層 報文消息(message)

TCP/IP 協議棧

協議層 傳輸方式
網絡接口層 以太網, WIFI
網絡互連層 IP, 對應主機IP, 發送數據包
傳輸層 TCP, UDP ,對應端口,
應用層 HTTP,FTP, DNS

TCP與UDP區別

TCP(傳輸控制協議)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議

  1. 面向鏈接
  2. 傳輸可靠
  3. 保準傳輸順序

UDP(用戶數據報協議)是OSI參考模型中一種無鏈接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務。

  1. 面向非鏈接
  2. 傳輸不可靠
  3. 速度很是快

HTTP,FTP,TELENET, SSH 屬於TCP, ping命令屬於 UDP

解釋一下TCP的三次握手和四次揮手

三次握手和四次揮手原理

Linux

查找端口服務對應的進程

  • lsof 查找哪些端口占用的進程

    • sudo lsof -i:80 查找使用80端口的進程
    • lsof -u www 查找用戶www的進程打開的文件
  • netstat 顯示與IP、TCP、UDP和ICMP協議相關的統計數據

    • netstat -lntp 查看開啓了哪些端口

查看內存佔用和CPU使用的命令

  • top 查看CPU顯示情況

    • top -u www 查看用戶www的的CPU 內存使用狀況
  • pmap 根據進程查看內存狀況
  • free 可用內存大小

    • free -m MB爲單位
    • free -g GB爲單位

PHP

單例模式

實現遠程加載圖片資源, 考慮refer的狀況

PHP的內存回收機制

算法

  1. 常見排序算法
  2. 快速排序算法的時間複雜度
  3. 如何實現二分排序

引用文章

-------------------------分割線-------------------------
問題的答案會不按期補全
歡迎你們指正,能學到東西就是好的

相關文章
相關標籤/搜索