第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):javascript
前端早早聊大會,與掘金聯合舉辦。加 codingdreamer 進大會技術羣,贏在新的起跑線, 全部往期都有全程錄播,上手年票一次性解鎖所有前端
本文是第二十二屆 - 前端早早聊面試方法專場,也是早早聊第 157 場,來自盒馬高級專家-宗羽 的分享。java
很普通的一道題git
// 假設本地機器沒法作加減乘除運算,須要經過遠程請求讓服務端來實現。
// 以加法爲例,現有遠程API的模擬實現
const addRemote = async (a, b) => new Promise(resolve => {
setTimeout(() => resolve(a + b), 1000)
});
// 請實現本地的add方法,調用addRemote,能最優的實現輸入數字的加法。
async function add(...inputs) {
// 你的實現
}
// 請用示例驗證運行結果:
add(1, 2)
.then(result => {
console.log(result); // 3
});
add(3, 5, 2)
.then(result => {
console.log(result); // 10
})
複製代碼
答案一 最基本的答案,若是寫不出來,那大機率是經過不了了github
async function add(...args) {
let res = 0;
if (args.length <= 2) return res;
for (const item of args) {
res = await addRemote(res, item);
}
return res;
}
複製代碼
遞歸版本web
async function add(...args) {
let res = 0;
if (args.length === 0) return res;
if (args.length === 1) return args[0];
const a = args.pop();
const b = args.pop();
args.push(await addRemote(a, b));
return add(...args);
}
複製代碼
常見的問題:面試
答案二 有候選人的答案以下:算法
// Promise鏈式調用版本
async function add(...args) {
return args.reduce((promiseChain, item) => {
return promiseChain.then(res => {
return addRemote(res, item);
});
}, Promise.resolve(0));
}
複製代碼
從這個實現能夠看出:後端
這個版本至少能到 70 分數組
答案三 以前的答案結果都是對的,可是咱們把耗時打出來,能夠看到耗時和參數個數成線性關係,由於全部計算都是串行的,顯然不是最優的解
更好一點的答案:
function add(...args) {
if (args.length <= 1) return Promise.resolve(args[0])
const promiseList = []
for (let i = 0; i * 2 < args.length - 1; i++) {
const promise = addRemote(args[i * 2], args[i * 2 + 1])
promiseList.push(promise)
}
if (args.length % 2) {
const promise = Promise.resolve(args[args.length - 1])
promiseList.push(promise)
}
return Promise.all(promiseList).then(results => add(...results));
}
複製代碼
能夠看到很明顯的優化。
答案四 還能再優化嗎? 有些同窗會想到加本地緩存
const cache = {};
function addFn(a, b) {
const key1 = `${a}${b}`;
const key2 = `${b}${a}`;
const cacheVal = cache[key1] || cache[key2];
if (cacheVal) return Promise.resolve(cacheVal);
return addRemote(a, b, res => {
cache[key1] = res;
cache[key2] = res;
return res;
});
}
複製代碼
加了緩存之後,咱們再第二次執行相同參數加法時,能夠不用請求遠端,直接變成毫秒級返回
還能再優化嗎?交給你們去思考
有些時候會讓候選人將代碼提交到 Github 倉庫,以工做中一個實際的模塊標準來開發,能夠考察:
實際題目
// 有一個 10G 文件,每一行是一個時間戳,
// 如今要在一臺 2C4G 的機器上對它進行排序,輸出排序之後的文件
// 案例輸入
// 1570593273487
// 1570593273486
// 1570593273488
// …
// 輸出
// 1570593273486
// 1570593273487
// 1570593273488
// …
複製代碼
先看一個答案,看看哪裏有問題
async function sort(inputFile, outputFile) {
const input = fs.createReadStream(inputFile);
const rl = readline.createInterface({ input });
const arr = [];
for await (const line of rl) {
const item = Number(line);
arr.push(item);
}
arr.sort((a, b) => a - b);
fs.writeFileSync(outputFile, arr.join('\n'));
}
複製代碼
10GB 的文件沒法一次性放進內存裏處理,內存只有 4GB
再看一個神奇的答案,只有一行代碼,並且從結果來講是正確的。但不是咱們筆試想要的答案。
const cp = require('child_process');
function sort(inputFile, outputFile) {
cp.exec(`sort -n ${inputFile} > ${outputFile}`);
}
複製代碼
解題思路
再將問題拆解
本題最難的點在於如何合併全部小文件。代碼如何實現?
堆有一些特性:
咱們嘗試把下面數組構形成一個最小堆
完整的實現參考:github.com/gxcsoccer/e…
「數據分析不是某個固定的職位,而是人工智能時代的通用能力」
第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):