前言:暫時先粗解10題。題目會不按期更新(解題若有誤,可在評論區貼出~你們共同窗習進步)node
/**
* 【模擬Promise】
*/
class myPromise {
constructor(callback) {
this.status = 'pending'
this.resMsg = ''
this.errMsg = ''
this.successCallBack = null
this.errCallBack = null
callback((res) => {
this.resMsg = res
this.successCallBack && this.successCallBack(this.resMsg) // pending ==> resolved 狀態時, 如有暫存回調函數, 讀取暫存回調函數
this.status = 'resolved'
}, (err) => {
this.errMsg = err
this.errCallBack && this.errCallBack(this.errMsg)
this.status = 'rejected'
})
this.callback = callback
}
then(successCallBack) {
console.log('---- then ---', this.status)
if(this.status === 'resolved') {
successCallBack(this.resMsg)
}
if(this.status === 'pending') {
console.log(successCallBack)
this.successCallBack = successCallBack // 若是還在pending狀態,先暫存回調函數
}
return this;
}
catch(errCallBack) {
console.log('---- catch ---', this.status)
if(this.status === 'rejected') {
errCallBack(this.errMsg)
}
if(this.status === 'pending') {
console.log(errCallBack)
this.errCallBack = errCallBack
}
return this;
}
}
/**
* 測試用例一
*/
new myPromise((resolve, reject) => {
setTimeout(() => {
resolve('測試success')
}, 2000)
}).then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
/**
* 測試用例二
*/
new myPromise((resolve, reject) => {
setTimeout(() => {
reject('測試error')
}, 5000)
}).then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
複製代碼
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 3000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 4000);
})
let p3 = Promise.reject('失敗')
/**
* 【模擬Promise.all】
*/
class myPromise{
constructor() {
}
static all(promises) {
// 確保promises爲array
if(!Array.isArray(promises)) {
throw new Error('大哥,麻煩輸入promise數組啊')
}
let results = []
let isRejected = false
return new Promise((resolve, reject) => {
promises.map((item, index) => {
item.then(res => {
if(!isRejected) {
results.push(res)
if(index === promises.length - 1) {
promises.length === results.length && resolve(results)
}
}
}).catch(err => {
reject(err)
isRejected = true
})
})
})
}
}
myPromise.all([p1,p2]).then(res => {
console.log(res, 'res1')
}).catch(err => {
console.log(err, 'err1')
})
myPromise.all([p1,p2,p3]).then(res => {
console.log(res, 'res2')
}).catch(err => {
console.log(err, 'err2')
})
複製代碼
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 3000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失敗了')
}, 1000);
})
class myPromise{
constructor() {
}
static race(promises) {
// 確保promises爲array
if(!Array.isArray(promises)) {
throw new Error('大哥,麻煩輸入promise數組啊')
}
let hasResult = false
return new Promise((resolve, reject) => {
promises.map((item, index) => {
item.then(res => {
hasResult || resolve(res)
hasResult = true
}).catch(err => {
hasResult || reject(err)
hasResult = true
})
})
})
}
}
myPromise.race([p1,p2]).then(res => {
console.log(res, 'res1')
}).catch(err => {
console.log(err, 'err1')
})
複製代碼
// Tips: 併發20個promise,併發上限是10個,隊列先入隊前10個promise,其中有promise執行成功,隊列外剩餘的promise依次入隊(保證隊列中始終保持10個上限)web
// 生成promise
const fetch = (duration , index) => {
return function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({duration, index})
}, duration);
})
}
}
/**
* 控制promise併發數 (暫時默認所有 success)
* Tips: Promise實例化後,即開始執行。因此promise數超上限時,暫時解決方案是:先初始化limit個promise,以後
*
* @param {Number} total 總promise條數
* @param {Number} max 最大併發數
* @param {Funtion} callback 全部promise執行後的回調
* @return
*/
const concurrencyFetch = (total, max, callback) => {
let currentFetchs = [];
let maxlen = Math.min(total, max)
let i = 0;
fetchs = initPromises(total)
// 請求數 未達到併發上限, 直接走promise.all便可
if(fetchs.length < max) {
Promise.all(fetchs.reduce((total, item) => {
return [...total, item.pro()]
}, [])).then(() => {
callback('所有執行完了')
})
return false;
}
currentFetchs = fetchs.slice(0, max)
// 達到最大併發數
function concurrencyLimit() {
/* currentFetchs.splice() */
/* let currentFetchs = fetchs.slice(i, i + max) */
/* console.log('---------達到併發瓶頸了---------', i, fetchs) */
console.log('當前---', i, currentFetchs)
debugger
Promise.race(currentFetchs.reduce((total, item) => {
return [...total, item.pro()]
}, [])).then((res) => {
if(max + i < total) {
const removeIndex = currentFetchs.findIndex(item => item.index === res.index)
let fastPromise = currentFetchs.splice(removeIndex, 1)
console.log('移除隊列中最快執行的promise:', fastPromise)
i++;
currentFetchs = [...currentFetchs, fetchs[max + i - 1]]
concurrencyLimit()
} else {
// 已經所有塞入 currentFetchs隊列
Promise.all(currentFetchs.reduce((total, item) => {
return [...total, item.pro()]
}, [])).then(() => {
callback('所有執行完了')
})
}
})
}
concurrencyLimit()
}
// 生成promise list
const initPromises = (len, startIndex = 0) => {
let arr = [];
new Array(len).fill('').map((_ , i) => {
let randomNum = Math.floor(Math.random()*10 + 1) * 1000
arr.push({pro: fetch(randomNum, startIndex + i), index: startIndex + i, randomNum})
})
console.log('生成的promise列表: ', arr)
return arr
}
concurrencyFetch(15 , 10, (res) => {
console.log(res, '都ok了~')
})
複製代碼
// Tips: 暫時只想到兩種,有其餘方案的能夠評論區留言哈~數組
實現方案一:(async await | promise) 我的感受是最容易想到的方案promise
/**
* 線程阻塞
*
* @param {Number}
* @return
*/
const sleep = async (delay) => {
const pro = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`----- 線程阻塞 ${delay/1000} s了 -----`)
}, delay);
})
const res = await pro
console.log(res)
}
複製代碼
實現方案二:(時間戳) 瀏覽器
const sleep = async (delay) => {
const startTime = new Date().getTime();
console.log(startTime)
while(new Date().getTime() - startTime < delay) {
continue
}
console.log(`----- 線程阻塞 ${delay/1000} s了 -----`)
}
複製代碼
LazyMan(「Hank」)輸出: Hi! This is Hank!bash
LazyMan(「Hank」).sleep(10).eat(「dinner」) 輸出 Hi! This is Hank! //等待10秒.. Wake up after 10 Eat dinner~閉包
LazyMan(「Hank」).eat(「dinner」).eat(「supper」) 輸出 Hi This is Hank! Eat dinner~ Eat supper~併發
以此類推。dom
class LazyMan {
constructor(name) {
this.name = name
this.asyncFun = Promise.resolve(this)
console.log(`--------- Hi This is ${this.name}! ---------`)
}
sleep(delay) {
console.log('sleep')
this.asyncFun = this.asyncFun.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`--------- Wake up after ${delay/1000}s ----------`)
resolve()
}, delay);
})
})
return this; //提供 」鏈式調用「
}
eat(food) {
console.log('eat')
this.asyncFun = this.asyncFun.then(res => {
console.log(`--------- Eat ${food}~ ---------`)
return Promise.resolve()
})
return this;
}
}
new LazyMan('小菜比').sleep(4000).eat('豆漿').eat('油條').sleep(2000).eat('炒年糕')
複製代碼
舉個例子:衝啊,兄弟們,拿lol首勝賺金幣了。。。騰訊baba爲了防止你被拉去楊教授那電療,首勝的週期是一天一次。若是不設置週期,每盤都能觸發首勝。。。你怕是要累趴在電腦前。。。 這就是咱們傳說中的 節流 async
/**
* 節流
*
* @param {Function} fn 須要節流的函數
* @param {Number} duration 觸發fn間隔時間, 單位ms
* @param {Boolean} immediately 是否當即執行
* @return
*/
function throttle (fn, duration, immediately = true) {
let timer = null
// 爲啥用閉包??? 把局部變量駐留在內存,避免使用全局變量
return function() {
if(!timer) {
if(immediately) {
fn()
timer = setTimeout(() => {
timer = null
}, duration);
} else {
timer = setTimeout(() => {
fn()
timer = null
}, duration);
}
}
}
}
function show() {
console.log('優雅的切圖仔')
}
setInterval(throttle(show, 5000, true), 1000);
複製代碼
舉個例子: 我要減肥(固然博主並不須要減肥,反而須要增肥,哈哈)???立個flag...勞資15天不吃肉!誰吃誰煞b。。一天兩天我咬牙堅決信念,終於13天過去了,第十四天(我。。。實在忍忍忍不住了,偷偷吃了包豬肉鋪,nice成功「破戒了」,15天flag從新刷新,前功盡棄咯。。。) 這就是咱們傳說中的 防抖
/**
* 防抖
*
* @param {Function} fn 須要防抖的函數
* @param {Number} duration 禁止觸發fn的間隔, 單位ms
* @param {Boolean} immediately 是否當即執行
* @return
*/
function debounce(fn, duration, immediately = true) {
let timer = null
// 爲啥用閉包??? 把局部變量駐留在內存,避免使用全局變量
return function() {
if(immediately) {
timer ? clearTimeout(timer) : fn()
timer = setTimeout(() => {
timer = null
}, duration);
} else {
timer && clearTimeout(timer)
timer = setTimeout(() => {
timer = null
fn()
}, duration);
console.log(timer)
}
}
}
複製代碼
function add(...args) {
let radixPointArr = args.reduce((total, item) => {
item = '' + item
let itemRadixPoint = item.indexOf('.')
if(itemRadixPoint >= 1) {
return [...total, item.length - itemRadixPoint - 1]
} else {
return [...total, 0]
}
}, [])
const radixLen = Math.max(...radixPointArr)
const result = args.reduce((total,item) => {
return total + item * Math.pow(10,radixLen)
}, 0)
return result / Math.pow(10,radixLen)
}
add(0.1,0.222,0.3, 3232, 0.66666)
複製代碼
/**
* 【localStorage設置時效性】
*
* Tips: 這個就不要在node裏跑了。web storage 針對瀏覽器~
* @param {String} key
* @param {Any} value
* @param {Number} expired 保質期 單位「秒」(這時候,一批吃貨投來「不屑」的目光)
*/
class myStorage {
constructor() {
}
// 默認無限大,暫時就99999999s吧~
static set(key, value, expired = 99999999) {
localStorage.setItem(key, JSON.stringify({
value,
expiredTimestamp: new Date().getTime() + expired * 1000
}));
}
static get(key) {
if(localStorage.getItem(key)) {
let result = JSON.parse(localStorage.getItem(key))
console.log(result)
const nowTimestamp = new Date().getTime()
if(nowTimestamp > result.expiredTimestamp) {
console.log('都過時了,看你妹啊~')
this.remove(key)
} else {
console.log(result.value)
}
} else {
console.log('storage已經被刪除了,趕忙去建立一個吧~')
}
}
static remove(key) {
localStorage.getItem(key) && localStorage.removeItem(key)
}
}
myStorage.set('name', '我是小菜比', 10)
myStorage.get('name')
複製代碼
實現add(1)(2)(3) = 6; add(1, 2, 3)(4) = 10; add(1)(2)(3)(4)(5) = 15;
複製代碼