[記錄]我的日常隨筆

HTTP

  • [緩存相關]
  • 講一講強緩存和協(xié)議緩存儡羔?
  • 有了【Last-Modified毛俏,If-Modified-Since】為何還要有【ETag奔则、If-None-Match】
  • 有關 HTTP 緩存的首部字段說一下
  • [TCP/IP 相關]
  • HTTP 和 TCP 的區(qū)別
  • TCP 三次握手和四次揮手技即?以其存在意義。
  • 在一次傳輸中它是如何保證每個數(shù)據(jù)包之間的順序的绳瘟?
  • [HTTP 相關]
  • HTTP 請求的什么時候用的對稱加密什么時候非對稱加密
  • HTTP 中的 keep-alive 有了解嗎雕憔?
  • HTTP2 特性
  • HTTP/2 對比 HTTP1.1
  • HTTP/2 都有哪些特性?頭部壓縮的原理糖声?
  • HTTP/2 是怎么解決隊頭阻塞的
  • HTTP/2 是如何壓縮頭部的
  • HTTPS 握手
  • 具體說一下 HTTP/2 中的多路復用
  • GET 和 POST 的區(qū)別
  • GET 就一定是冪等的嗎斤彼?
  • 狀態(tài)碼。302.304.301.401.403 的區(qū)別蘸泻?
  • 狀態(tài)碼畅卓。204 和 304 分別有什么作用?
  • HTTP 和 HTTPS 握手差異蟋恬?
  • 為什么說 HTTPS 比 HTTP 安全呢
  • 簡單講了一下非對稱加密的握手過程
  • 證書簽名過程和如何防止被串改
  • TCP/IP 網絡分層模型是怎樣分層的
  • OSI 網絡分層模型是怎樣分層的
  • TCP 和 UDP 區(qū)別
  • HTTP/0.9、HTTP/1.0趁冈、HTTP/1.1歼争、HTTP/2、HTTP/3 各版本之間的區(qū)別渗勘?
  • [綜合相關]
  • CSRF 跨站請求偽造和 XSS 跨站腳本攻擊是什么沐绒?
  • 如果讓你去實現(xiàn)一個 CSRF 攻擊你會怎做?
  • 如果使用 jsonp 的話會有什么安全問題嗎旺坠?
  • 你是如何解決跨域的乔遮?都有幾種?
  • 為什么說 GET 會留下歷史記錄取刃?
  • 從“在瀏覽器輸入域名”到“頁面靜態(tài)資源完全加載”的整個流程
  • 假設有兩個子項目蹋肮,他們需要共用同一個用戶體系如何保證關掉頁面之后打開另一個項目用戶還是登錄狀態(tài)?

JS

  • Promise 實現(xiàn)
  • Generator 實現(xiàn)
  • async璧疗、await 實現(xiàn)
  • 垃圾回收中的堆和棧的區(qū)別
  • 0.1 + 0.2 != 0.3 背后的原理坯辩?
  • 手寫 vue2/3 具體實現(xiàn)
  • 手寫繼承
  • requestAnimationFrame 屬于宏任務還是微任務
  • 動態(tài)表單實現(xiàn)
  • null 為什么被 typeof 錯誤的判斷為了'object'
  • 洋蔥模型
  • 實現(xiàn)對象深拷貝
  • 實現(xiàn)數(shù)組去重
  • 實現(xiàn)一個 apply/call/bind 方法
  • 實現(xiàn)一個函數(shù),URL 參數(shù)解析為對象
  • 實現(xiàn)一個 trim
  • 實現(xiàn)柯理化函數(shù)
  • 實現(xiàn) loadsh 的 get 方法 (_.get('a.b.c'))
  • 查找字符串中的最長無重復子串
  • 兩個數(shù)組的并集與交集
  • 排序算法實現(xiàn)
  • 數(shù)組扁平化

Vue

  • 雙向綁定原理
  • nextTick 原理
  • nextTick 中的 waiting 是什么時候變?yōu)?true 的呢
  • 虛擬 DOM
  • Object.defineProperty()有什么缺點崩侠?Vue3 為什么用 Proxy
  • Vue3 有哪些新的 API 或者有做哪些優(yōu)化漆魔?
  • 說一下 Vue 的 diff 算法
  • diff 算法的缺點

Devops

  • webpack 的構建流程、自定義 loader,插件原理改抡、HMR 的實現(xiàn)矢炼、打包原理,常用的插件以及性能優(yōu)化
  • 單元測試做過嗎阿纤?你是怎么做的?
  • 對 tree-shaking 的了解(雖然生產模式下默認開啟句灌,但是由于經過 babel 編譯全部模塊被封裝成 IIFE IIFE 存在副作用無法被 tree-shaking 掉 需要配置 { module: false }和 sideEffects: false rollup 和 webpack 的 shaking 程度不同,以一個 Class 為例子)
  • webpack-dev-server 原理和如何處理跨域

書單

  • 《 網絡是怎樣連接的 》
  • 《 圖解 HTTP 》
  • 《 圖解 TCP/IP 》
  • 《 極客時間- 透視 HTTP 協(xié)議 》
  • 《 TCP/IP 詳解(第一卷)》
  • 《 瀏覽器原理 》
  • 《 DevOps 實戰(zhàn)筆記 》
  • 《 Nginx 核心知識 100 講 》
  • 《 學習 Javascipt 數(shù)據(jù)結構與算法 》
  • 《 JavaScript 版 數(shù)據(jù)結構與算法 》
  • 《 極客時間- 數(shù)據(jù)結構與算法之美 》
  • 《 極客時間- 算法面試通關 》

代碼實現(xiàn)

  1. 手寫節(jié)流防抖
/**
 * 節(jié)流
 * @param {Func} callback 需要節(jié)流的函數(shù)
 * @param {Number} wait 等待毫秒數(shù)
 * 執(zhí)行一次后阵赠,一段時間內不再執(zhí)行
 */
function throttle(func, wait) {
  let timer = null;
  return function (...args) {
    if (timer === null) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, wait);
    }
  };
}
/**
 * 防抖
 * @param {Func} callback 需要防抖的函數(shù)
 * @param {Number} wait 等待毫秒數(shù)
 * 一段時間內涯塔,取最后一次執(zhí)行
 */
function debounce(func, wait) {
  let timer = null;
  return function (...args) {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      func.apply(this, args);
    }, wait);
  };
}
  1. 圣杯與雙飛翼布局
/** 圣杯 **/
<div class="wrapper1">
  <div class="main">
    <p>bilibili</p>
  </div>
  <div class="left"></div>
  <div class="right"></div>
</div>
<style>
  .wrapper1 {
    padding: 0 60px 0 30px;
  }
  .wrapper1 .main {
    float: left;
    width: 100%;
    height: 300px;
    background: red;
  }
  .wrapper1 .left {
    float: left;
    width: 30px;
    margin-left: -100%;
    background: blue;
    height: 100px;
    position: relative;
    right: 30px;
  }
  .wrapper1 .right {
    float: left;
    width: 60px;
    margin-left: -60px;
    background: yellow;
    height: 200px;
    position: relative;
    left: 60px;
  }
</style>

/** 雙飛翼 **/
<div class="wrapper2">
  <div class="container">
    <div class="main">
      <p>bilibili</p>
    </div>
  </div>
  <div class="left"></div>
  <div class="right"></div>
</div>
<style>
  .wrapper2 {
    min-width: 630px;
  }
  .wrapper2 .container {
    float: left;
    width: 100%;
  }
  .wrapper2 .container .main {
    height: 300px;
    background: red;
    margin: 0 600px 0 30px;
  }
  .wrapper2 .left {
    float: left;
    width: 30px;
    background: blue;
    height: 100px;
    margin-left: -100%;
  }
  .wrapper2 .right {
    float: left;
    width: 600px;
    background: yellow;
    height: 200px;
    margin-left: -600px;
  }
</style>
  1. 數(shù)組長度為 5 且元素的隨機數(shù)在 2-32 間不重復的值
// 生成 [n,m] 的隨機整數(shù)
const creatRandomNum = (min,max) => parseInt(Math.random()*(max-min+1)+min);
function arr5(arr=[]) {
    if(arr.length >= 5){return arr};
    arr = [...new Set([...arr, creatRandomNum(2,32)])];
    return arr5(arr);
}

4.寫一個獲取當前 url 查詢字符串中的參數(shù)的方法

const getUrlQuery = (url = location.href) => {
  try {
    return [...new URL(url).searchParams].reduce(
      (pre, [key, value]) => Object.assign(pre, { [key]: value }),
      {},
    );
  } catch {
    throw new Error(`url格式不正確。url: ${url}`);
  }
};
  1. html5 中的 form 怎么關閉自動完成清蚀?
// 在 input 標簽中匕荸,可以設置 autocomplete="off" 來關閉自動填充。
<form action="demo_form.html" method="get" autocomplete="off">
  First name:<input type="text" name="fname" /><br />
  E-mail: <input type="email" name="email" /><br />
  <input type="submit" />
</form>
  1. 請說說<script>枷邪、<script async>和<script defer>的區(qū)別
1.script 同步下載榛搔,下載成功繼續(xù)阻塞 DOM 的渲染,立即執(zhí)行东揣。
2. async異步下載践惑,下載成功后阻塞 DOM 的渲染,立即執(zhí)行嘶卧。
3. defer異步加載尔觉,下載成功后等待文檔加載,文檔加載完成后執(zhí)行芥吟。
4.async侦铜、defer這兩個屬性無法應用于內聯(lián)script。
image
  1. 實現(xiàn)一個 call / apply / bind / new
// call
Function.prototype.call2 = function (target, ...args) {
  target._func = this;
  const ret = target._func(...args);
  delete target._func;
  return ret;
};
// apply
Function.prototype.apply2 = function (target, args=[]) {
  target._func = this;
  const ret = target._func(...args);
  delete target._func;
  return ret;
};
// bind
Function.prototype._bind = function (target, ...res) {
    if (typeof this !== 'function') {
      throw new TypeError('Error')
    }
    const that = this;
    const _func = function(...args) {
        // 判斷當前函數(shù)是直接訪問還是通過new進行構造
        return that.apply(this instanceof _func ? this : target, res.concat(args));
    }
    // 添加一層原型钟鸵,防止修改_func.prototype時影響到this.prototype
    _func.prototype = Object.create(this.prototype);
    return _func;
}
// new
function _new(target, ...args) {
    const obj = Object.create(target.prototype);
    const ret = target.apply(obj, args);
    return typeof ret === 'object' ? ret : obj;
}

8.Object.create 的模擬實現(xiàn)

Object.create = function(target) {
  function _func () {};
  _func.prototype = target;
  return new _func();
}
  1. instanceof 模擬實現(xiàn)
function _instanceof(left, right) {
  let proto = left.__proto__;
  let prototype = right.prototype;
  while (true) {
    if (proto === null) return false;
    if (proto === prototype) return true;
    proto = proto.__proto__;
  }
}

10.解釋一個為什么 10.toFixed(10)會報錯钉稍?

/**
在我們的直覺上,10.toFixed(10) 是把整數(shù)的 10 轉為浮點數(shù)并且保留 10 位小數(shù)部分棺耍。

但實際上會出錯贡未,是因為 JS 的解釋器對 . 操作符產生了歧義。
在 JS 中 . 可以表示小數(shù)和從對象中取值蒙袍。在這個例子中俊卤, 由于 10 是整數(shù),
所以在 10. 默認是小數(shù)點左敌,因此會報錯瘾蛋。
**/

// 解決的辦法有下面幾種:
(10).toFixed(10) 個人喜歡這種,看起來舒服一點
10..toFixed(10)

11.將 Object 與 Map 互轉

var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));// Map { foo: "bar", baz: 42 }
var obj2 = Object.fromEntries(map);// {foo: "bar", baz: 42}

12.寄生組合式繼承

// 通過構造函數(shù)來繼承實例屬性矫限,通過原型鏈的混成形式來繼承原型方法
function clonePrototype(Super,Suber){
   var prototype = Object.create(Super.prototype);
   prototype.constructor = Suber;
   Suber.prototype = prototype;
}

function Super(name){
  this.name = name
  this.like = ['sing','dance','rap','basketball']
}
Super.prototype.sayName=function(){
   console.log(this.name)
}

function Suber(name,age){
   Super.call(this,name)      //  繼承屬性
   this.age=age
}
clonePrototype(Super,Suber);
Suber.prototype.sayAge=function(){
  console.log(this.age)
}

var sub1 = new Suber('sss',18);
console.log(sub1.name);  // -> sss
sub1.sayName();  // -> sss
sub1.sayAge();   // -> 18

13.如何讓 (a == 1 && a == 2 && a == 3) 的值為 true哺哼?

var a = {
  valueOf: (function () {
    let i = 1;
    //閉包的特性之一:i 不會被回收
    return function () {
      return i++;
    }
  })()
}
console.log(a == 1 && a == 2 && a == 3); // true
  1. JS 模塊化
AMD: require.js 為代表佩抹,依賴前置,一律先加載再使用取董。
CMD: sea.js 為代表棍苹,依賴就近原則。
UMD: 兼容AMD和commonJS規(guī)范的同時茵汰,還兼容全局引用的方式枢里。
ES6 import/export

15.你從未注意的隱藏危險: target = "_blank" 和 "opener"

// 最佳實踐
<a  target="_blank"
   rel="noopener noreferrer nofollow">
  Enter an "evil" website
</a>

16.階乘

function factorial(num, sum = 1) {
    if(num <= 1)return sum;
    sum *= num;
    return factorial(--num, sum); // 尾遞歸
}
factorial(3) // -> 6

17.柯里化

const curry = (fn , args = []) => {
    return (...rets) => {
        const allArgs = args.concat(rets);
        if(allArgs.length < fn.length) {
            return curry(fn, allArgs);
        } else {
            return fn.apply(this, allArgs);
        }
    }
}
function multiFn(a, b, c) {
    return a * b * c;
}

var multi = curry(multiFn);

multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);

  1. 「中高級前端面試」JavaScript 手寫代碼無敵秘籍

  2. 實現(xiàn)一個 Promise 《圖解 Promise 實現(xiàn)原理

// Promise 簡單的實現(xiàn)
function APromise(fn) {
  const that = this;
  that.status = "pending"; // Promise初始狀態(tài)為pending
  that.data = undefined; // Promise的值
  that.resCbs = []; // APromise resolve回調函數(shù)集合
  that.rejCbs = []; // APromise reject回調函數(shù)集合

  function resolve(data) {
    if (that.status === "pending") {
      that.status = "resolved";
      that.data = data;
      setTimeout(() => {
        that.resCbs.forEach((cb) => cb(data));
      });
    }
  }

  function reject(data) {
    if (that.status === "pending") {
      that.status = "rejected";
      that.data = data;
      setTimeout(() => {
        that.rejCbs.forEach((cb) => cb(data));
      });
    }
  }

  try {
    fn(resolve, reject); // 執(zhí)行傳進來的函數(shù),傳入resolve, reject參數(shù)
  } catch (e) {
    reject(e);
  }
}

APromise.prototype.then = function (onRes = (v) => v, onRej = (j) => j) {
  const that = this;

  if (that.status === "resolved") {
    // 這里promise的狀態(tài)已經確定是resolved蹂午,所以調用onResolved
    return new APromise((resolve, reject) => {
      setTimeout(() => {
        try {
          // ret是onRes的返回值
          const ret = onRes(that.data);
          if (ret instanceof APromise) {
            // 如果ret是一個promise栏豺,則取其值作為新的promise的結果
            ret.then(resolve, reject);
          } else {
            // 否則,以它的返回值作為新的promise的結果
            resolve(ret);
          }
        } catch (e) {
          // 如果出錯豆胸,以捕獲到的錯誤作為promise2的結果
          reject(e);
        }
      });
    });
  }

  // 這里的邏輯跟前面一樣奥洼,不再贅述
  if (that.status === "rejected") {
    return new APromise((resolve, reject) => {
      setTimeout(() => {
        try {
          const ret = onRej(that.data);
          if (ret instanceof APromise) {
            ret.then(resolve, reject);
          } else {
            reject(ret);
          }
        } catch (e) {
          reject(e);
        }
      });
    });
  }

  if (that.status === "pending") {
    // 如果當前的Promise還處于pending狀態(tài),則不能確定調用
    // onResolved還是onRejecte晚胡,只能等到Promise狀態(tài)確定后灵奖,
    // 才能確定如何處理
    return new APromise((resolve, reject) => {
      that.resCbs.push(() => {
        setTimeout(() => {
          try {
            const ret = onRes(that.data);
            if (ret instanceof APromise) {
              ret.then(resolve, reject);
            } else {
              resolve(ret);
            }
          } catch (e) {
            reject(e);
          }
        });
      });

      that.rejCbs.push(() => {
        setTimeout(() => {
          try {
            const ret = onRej(that.data);
            if (ret instanceof APromise) {
              ret.then(resolve, reject);
            } else {
              reject(ret);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    });
  }
};

// 順便實現(xiàn)一下catch方法
APromise.prototype.catch = function (onRej) {
  return this.then(null, onRej);
};

const p = new APromise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 2000);
});

p.then(function (v) {
  console.log(v);
  return 2;
})
  .then(function (v) {
    console.log(v);
    return new APromise(function (resolve, reject) {
      setTimeout(function () {
        resolve(3);
      }, 3000);
    });
  })
  .then(function (v) {
    console.log(v);
  });


/**
 *實現(xiàn)promise中的all方法
 */
Promise.prototype.all = function (array) {
  judgeType(array);
  let count = 0;
  const total = array.length;
  const ret = [];
  return new Promise((resolve, reject) => {
    array.forEach((element) => {
      element.then((res) => {
        ret.push(res);
        count++;
        if (count === total) {
          resolve(ret);
        }
      });
      element.catch((err) => {
        reject(err);
      });
    });
  });
};
/**
 *類型的判斷
 */
function judgeType(array) {
  if (array instanceof Array) {
    array.forEach((item) => {
      if (!(item instanceof Promise)) {
        throw "該參數(shù)的每一項必須是Promise的實例";
      }
    });
  } else {
    throw "必須是數(shù)組哦";
  }
}

var p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);
all = function (promises) {
  const total = promises.length;
  const ret = [];
  let count = 0;
  return new Promise((resolve, reject) => {
    promises.forEach((item) => {
      item.then((res) => {
        ret.push(res);
        count++;
        if (count === total) {
          return resolve(ret);
        }
      });
      item.catch((err) => {
        return reject(err);
      });
    });
  });
};
all([p1, p2, p3]).then(function (results) {
    //then方法不會被執(zhí)行
    console.log(results);
}).catch(function (e){
    //catch方法將會被執(zhí)行,輸出結果為:2
    console.log(2);
});
/**
 *實現(xiàn)promise中的race方法
 */
Promise.prototype.race = function (promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((item) => {
      Promise.resolve(item).then(
        (res) => {
          return resolve(res);
        },
        (err) => {
          return reject(err);
        }
      );
    });
  });
};
var p1 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 500, "500");
});
var p2 = new Promise(function (resolve, reject) {
  setTimeout(resolve, 600, "600");
});
race([p1, p2]).then(function (result) {
  console.log(result); // '2018' 因為2018更快
});
/**
 *實現(xiàn)promise中的finally方法
 */
Promise.prototype.finally = function (onFinally) {
  return this.then(
    /* onFulfilled */
    (res) => Promise.resolve(onFinally()).then(() => res),
    /* onRejected */
    (err) =>
      Promise.resolve(onFinally()).then(() => {
        throw err;
      })
  );
};

// test
new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 500);
})
  .then((res) => {
    console.log(res);
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(2);
      }, 500);
    });
  })
  .then(console.log);

//Promise 完整的實現(xiàn)
class Promise {
  callbacks = [];
  state = 'pending';//增加狀態(tài)
  value = null;//保存結果
  constructor(fn) {
    fn(this._resolve.bind(this), this._reject.bind(this));
  }
  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      this._handle({
        onFulfilled: onFulfilled || null,
        onRejected: onRejected || null,
        resolve: resolve,
        reject: reject
      });
    });
  }
  catch(onError) {
    return this.then(null, onError);
  }
  finally(onDone) {
    if (typeof onDone !== 'function') return this.then();

    let Promise = this.constructor;
    return this.then(
      value => Promise.resolve(onDone()).then(() => value),
      reason => Promise.resolve(onDone()).then(() => { throw reason })
    );
  }
  static resolve(value) {
    if (value && value instanceof Promise) {
      return value;
    } else if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise(resolve => {
        then(resolve);
      });

    } else if (value) {
      return new Promise(resolve => resolve(value));
    } else {
      return new Promise(resolve => resolve());
    }
  }
  static reject(value) {
    if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise((resolve, reject) => {
        then(reject);
      });

    } else {
      return new Promise((resolve, reject) => reject(value));
    }
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let fulfilledCount = 0
      const itemNum = promises.length
      const rets = Array.from({ length: itemNum })
      promises.forEach((promise, index) => {
        Promise.resolve(promise).then(result => {
          fulfilledCount++;
          rets[index] = result;
          if (fulfilledCount === itemNum) {
            resolve(rets);
          }
        }, reason => reject(reason));
      })

    })
  }
  static race(promises) {
    return new Promise(function (resolve, reject) {
      for (let i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(function (value) {
          return resolve(value)
        }, function (reason) {
          return reject(reason)
        })
      }
    })
  }
  _handle(callback) {
    if (this.state === 'pending') {
      this.callbacks.push(callback);
      return;
    }

    let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;

    if (!cb) {//如果then中沒有傳遞任何東西
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
      cb(this.value);
      return;
    }

    let ret;

    try {
      ret = cb(this.value);
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
    } catch (error) {
      ret = error;
      cb = callback.reject
    } finally {
      cb(ret);
    }

  }
  _resolve(value) {
    if(this.state !== 'pending') return
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var then = value.then;
      if (typeof then === 'function') {
        then.call(value, this._resolve.bind(this), this._reject.bind(this));
        return;
      }
    }

    this.state = 'fulfilled';//改變狀態(tài)
    this.value = value;//保存結果
    this.callbacks.forEach(callback => this._handle(callback));
  }
  _reject(error) {
    if(this.state !== 'pending') return
    this.state = 'rejected';
    this.value = error;
    this.callbacks.forEach(callback => this._handle(callback));
  }
}
  1. 深拷貝
// 小細節(jié) -> 需要考慮一下循環(huán)引用的情況 -> WeakMap
function deepCopy(obj){
    let result;
    if(typeof obj == "object"){
        //復雜數(shù)據(jù)類型
       result = obj.constructor == Array ? [] : {};
        for(let i in obj){
            result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
        }
    }else {
       result = obj;
    }
    return result;
}

function deepCopy2(target, weakMaps = new WeakMap()) {
  if (typeof target !== "object" || target === null) {
    return target;
  }
  if (weakMaps.has(target)) return weakMaps.get(target);
  const res = Array.isArray(target) ? [] : {};
  weakMaps.set(target, res);
  for (let key in target) {
    res[key] = deepCopy(target[key], weakMaps);
  }
  return res;
}

21.瀏覽器進程與線程
https://imweb.io/topic/58e3bfa845e5c13468f567d5

22.設計一個簡單的任務隊列估盘,要求分別在 1,3,4 秒后打印出”1“瓷患,”2“,”3“

/**
 * 題目
 */
new Quene()
  .task(1000, () => {
    console.log(1);
  })
  .task(2000, () => {
    console.log(2);
  })
  .task(1000, () => {
    console.log(3);
  })
  .start();

function Quene() { ... }

/**
 * 解題1 promise
 */
class Quene {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({
      wait,
      fn,
    });
    return this;
  }
  async start() {
    for (let task of this.tasks) {
      const { wait, fn } = task;
      await new Promise((res, rej) => {
        setTimeout(() => {
          fn();
          res();
        }, wait);
      });
    }
  }
}

/**
 * 解題2 遞歸
 */
class Quene {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({ wait, fn });
    return this;
  }
  start() {
    const firstTask = this.tasks.shift();
    if (firstTask) {
      setTimeout(() => {
        firstTask.fn();
        this.start();
      }, firstTask.wait);
    }
  }
}

/**
 * 解題3 閉包
 */
class Queue {
  constructor() {
    this.tasks = [];
  }
  task(wait, fn) {
    this.tasks.push({
      wait,
      fn,
    });
    return this;
  }
  start() {
    let int = 0;
    this.tasks.forEach(({ wait, fn }) => {
      setTimeout(() => {
        fn();
      }, (int += wait));
    });
  }
}

  1. 用 setTimeout 實現(xiàn) setInterval遣妥,闡述實現(xiàn)的效果與 setInterval 的差異
function mySetInterval(fn, wait) {
    mySetInterval.timer = setTimeout(() => {
        fn();
        mySetInterval(fn, wait);
    }, wait)
}

mySetInterval.clear = function() {
    clearTimeout(mySetInterval.timer)
}

mySetInterval(() => {
    console.log(11111)
}, 1000)

setTimeout(() => {
    // 5s 后清理
    mySetInterval.clear()
}, 5000)
  1. vue3 中的數(shù)據(jù)偵測
const rawToReactive = new WeakMap();
const reactiveToRaw = new WeakMap();

/**
 * utils
 * */
function isObject(val) {
  return typeof val === "object";
}
function hasOwn(val, key) {
  const hasOwnProperty = Object.prototype.hasOwnProperty;
  return hasOwnProperty.call(val, key);
}

/**
 * traps
 * */
// get
function createGetter() {
  return function(target,key,receiver) {
    const res = Reflect.get(target,key,receiver);
    console.log('get', key);
    return isObject(res) ? reactive(res) : res;
  }
}
// set
function set(target,key,value,receiver) {
  const hadKey = hasOwn(target, key);
  const oldValue = target[key];
  value = reactiveToRaw.get(value) || value;
  const res = Reflect.set(target, key, value, receiver)
  if(!hadKey || value !== oldValue) {
    console.log('tigger...');
  }
  return res;
}
// handle
const mutableHandlers = {
  get: createGetter(),
  set: set
};
// create reactive object
function createReactiveObject(target, toProxy, toRaw, baseHandlers) {
  let observed = toProxy.get(target);
  // target 生成過 observed,返回 observed
  if(observed !== void 0) {
    return observed;
  };
  // target 是 observed, 返回 target
  if(toRaw.has(target)) {
    return target;
  }
  observed = new Proxy(target, baseHandlers);
  toProxy.set(target, observed);
  toRaw.set(observed, target);
  return observed;
}
// enter
function reactive(target) {
  return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers)
}
  1. Vue 的響應式原理中 Object.defineProperty 有什么缺陷沙咏?為什么在 Vue3.0 采用了 Proxy,拋棄了 Object.defineProperty?
  • 優(yōu)缺點
    1. Object.defineProperty 無法監(jiān)控到數(shù)組下標的變化故河,導致通過數(shù)組下標添加元素,不能實時響應鱼的;
    2. Object.defineProperty 只能劫持對象的屬性,從而需要對每個對象凑阶,每個屬性進行遍歷,如果宙橱,屬性值是對象蘸拔,還需要深度遍歷环葵。Proxy 可以劫持整個對象,并返回一個新的對象张遭。
    3. Proxy 不僅可以代理對象,還可以代理數(shù)組菊卷。還可以代理動態(tài)增加的屬性。
  1. 實現(xiàn) async await
function co(genFun) {
    return new Promise((resolve, reject) => {
        const gen = genFun();
        function next(...params){
            const {value, done} = gen.next(...params);
            if(done){
                return resolve(value)
            } else {
                value.then((...args)=>next(...args));
            }
        };
        next();
    })
};
// test
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000));
function* testG() {
  // await被編譯成了yield
  const data = yield getData()
  console.log('data: ', data);
  const data2 = yield getData()
  console.log('data2: ', data2);
  return 'success'
}
co(testG).then(res=>{console.log('res', res)});
// logs
data:  data
data2:  data
res success
  1. LazyMan
// 實現(xiàn)LazyMan
LazyMan('jack').sleep(3000).eat('籃球').eat('rap').eat('唱歉甚、跳')
// hi,I'm jack
// 阻塞3s
// 籃球
// rap
// 唱、跳

LazyMan('x1').eat('高').sleep(5000).eat('富').eat('帥')
// hi,I'm x1
// 高
// 阻塞5s
// 富
// 帥

LazyMan('lurenjia').sleepFirst(3000).eat('吹').eat('牛')
// 阻塞3s
// hi,I'm lurenjia
// 吹
// 牛

class CraeteLazyMan {
  constructor(name) {
    this.queue = [];
    const nameTask = () => {
      console.log(`ADI-LOG => name`, name);
      this.task();
    };
    this.queue.push(nameTask);
    setTimeout(() => {
      this.task();
    }, 0);
  }
  task() {
    const fun = this.queue.shift();
    fun && fun();
  }
  sleep(time) {
    const _task = () => {
      setTimeout(() => {
        this.task();
      }, time);
    };
    this.queue.push(_task);
    return this;
  }
  sleepFirst(time) {
    const _task = () => {
      setTimeout(() => {
        this.task();
      }, time);
    };
    this.queue.unshift(_task);
    return this;
  }
  eat(str) {
    const _task = () => {
      console.log(`ADI-LOG => eat`, str);
      this.task();
    };
    this.queue.push(_task);
    return this;
  }
}

function LazyMan(name = "") {
  return new CraeteLazyMan(name);
}


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末铃芦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子襟雷,更是在濱河造成了極大的恐慌刃滓,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耸弄,死亡現(xiàn)場離奇詭異咧虎,居然都是意外死亡,警方通過查閱死者的電腦和手機计呈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門砰诵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捌显,你說我怎么就攤上這事茁彭。” “怎么了扶歪?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵理肺,是天一觀的道長。 經常有香客問我善镰,道長妹萨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任炫欺,我火速辦了婚禮乎完,結果婚禮上,老公的妹妹穿的比我還像新娘品洛。我一直安慰自己树姨,他們只是感情好摩桶,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娃弓,像睡著了一般典格。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上台丛,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天耍缴,我揣著相機與錄音,去河邊找鬼挽霉。 笑死防嗡,一個胖子當著我的面吹牛,可吹牛的內容都是我干的侠坎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼他嫡,長吁一口氣:“原來是場噩夢啊……” “哼钢属!你這毒婦竟也來了淆党?” 一聲冷哼從身側響起讶凉,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荷憋,失蹤者是張志新(化名)和其女友劉穎台谊,沒想到半個月后譬挚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體减宣,經...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡漆腌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年塑径,在試婚紗的時候發(fā)現(xiàn)自己被綠了填具。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劳景。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡盟广,死狀恐怖筋量,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情肋拔,我是刑警寧澤玻募,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布跃惫,位于F島的核電站艾栋,受9級特大地震影響蝗砾,放射性物質發(fā)生泄漏。R本人自食惡果不足惜闲勺,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一菜循、第九天 我趴在偏房一處隱蔽的房頂上張望癌幕。 院中可真熱鬧,春花似錦橙喘、人聲如沸厅瞎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽身诺。三九已至抄囚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間穴亏,已是汗流浹背嗓化。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工刺覆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谦屑,地道東北人氢橙。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓悍手,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涝焙,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355