利用js實(shí)現(xiàn)可進(jìn)行時(shí)間和工作調(diào)度的任務(wù)管理器
前言
前幾天我們的同學(xué)在面試的時(shí)候提供了這樣一道有趣的面試題,實(shí)現(xiàn)一個(gè)可進(jìn)行時(shí)間和工作調(diào)度的任務(wù)管理器,具體題目如下,快來看看吧。
// 實(shí)現(xiàn)一個(gè) arrange 可以是函數(shù) / class,可以進(jìn)行時(shí)間和工作調(diào)度
// [ > ... ] 表示調(diào)用函數(shù)后的打印內(nèi)容
// 調(diào)用 arrange('William') 函數(shù)的時(shí)間加入一個(gè)任務(wù),調(diào)用 execute() 的時(shí)候執(zhí)行任務(wù)
// arrange('William').execute();
// 執(zhí)行的時(shí)候輸出這句話
// > William is notified
// 除了已上方式,還可以通過 do('commit') 追加任務(wù),在執(zhí)行
// arrange('William').do('commit').execute();
// 先輸出添加的任務(wù)
// > William is notified
// 在輸出追加的任務(wù)
// > Start to commit
// 還可以通過 wait(5) 在任務(wù)之間做間隔時(shí)間
// arrange('William').wait(5).do('commit').execute();
// 先輸出添加的任務(wù)
// > William is notified
// 等待 5秒
// 在輸出追加的任務(wù)
// > Start to commit
// 也可以通過 waitFirst(5) 在任務(wù)調(diào)用前設(shè)置等待時(shí)間
// arrange('William').waitFirst(5).do('push').execute();
// 等待 5秒
// 先輸出添加的任務(wù)
// > William is notified
// 在輸出追加的任務(wù)
// > Start to push
function arrange(taskId) {
// 此處寫代碼邏輯
}
// 或使用類組件,如果使用類組件,調(diào)用形式可以改為: new arrange(William'),execute();
class arrange { }任務(wù)管理器是一種可以讓你對(duì)一系列的任務(wù)進(jìn)行組織和執(zhí)行的工具,它可以讓你在添加任務(wù)、追加任務(wù)、設(shè)置任務(wù)間隔等方面有更多的自由度和靈活性。
比如,你可以用任務(wù)管理器來實(shí)現(xiàn)一個(gè)音樂播放器,一個(gè)文件上傳器,一個(gè)數(shù)據(jù)采集器等等。
聽起來很有用吧?那么我們就來看看具體的實(shí)現(xiàn)步驟吧。
設(shè)計(jì)思路
通過以上需求我們可以知道,我們需要一個(gè)數(shù)組來記錄它的任務(wù)列表。
無論我們是調(diào)用 arrange()、do()、wait() 還是 waitFirst(),都不會(huì)做任何事情,而是會(huì)產(chǎn)生一個(gè)任務(wù),把這個(gè)任務(wù)往數(shù)組里添加。
只有等到調(diào)用 execute() 的時(shí)候,才會(huì)真正的把這個(gè)數(shù)組里的任務(wù)依次拿出來執(zhí)行。
并且我們可以看到,arrange() 的調(diào)用,返回的值可以調(diào)用 do()、wait() 、waitFirst()和 execute() 方法,也就是說 arrange 函數(shù)的返回值包含這些函數(shù)。
它又是鏈?zhǔn)秸{(diào)用,所以說除了 execute 函數(shù)以外,每一個(gè)函數(shù)調(diào)用的返回值都是 arrange 函數(shù)的返回值。
大致邏輯就是這樣,我們一點(diǎn)一點(diǎn)去做。
代碼實(shí)現(xiàn)
function arrange(taskId) {
// 創(chuàng)建一個(gè)空數(shù)組 tasks 來存儲(chǔ)所有的任務(wù)
const tasks = [];
// 因?yàn)樵谡{(diào)用 arrange() 的時(shí)候就是添加一個(gè)任務(wù),并且任務(wù)可以被調(diào)用
// 也就是說任務(wù)就是一個(gè)函數(shù),并且執(zhí)行任務(wù)會(huì)輸出 “任務(wù)名 + is notified” 格式的字符串
// 所以我們?cè)谡{(diào)用時(shí)直接添加任務(wù)
tasks.push(() => {
console.log(`${taskId} is notified`);
});
// 聲明四個(gè)方法
function execute() {}
function doSomething() {
// 因?yàn)?do 是保留字,所以換一個(gè)名字
}
function wait() {}
function waitFirst() {}
// 返回四個(gè)方法
return {
execute,
do: doSomething,
wait,
waitFirst,
};
}接下來我們實(shí)現(xiàn)這四個(gè)方法。首先是 doSomething 方法( 因?yàn)?do 是保留字 ),它接受一個(gè)參數(shù) something,表示要追加的任務(wù)名。
然后它把任務(wù)( 也就是打印 Start to ${something})推入數(shù)組中。
最后它返回自身( 也就是包含四個(gè)方法的對(duì)象 ),以便于鏈?zhǔn)秸{(diào)用。
function doSomething(something) {
tasks.push(() => {
console.log(`Start to ${something}`);
});
return this;
}然后是 wait 方法,它接受一個(gè)參數(shù) duration,表示要等待的時(shí)間( 單位為秒 )。
然后它把任務(wù)( 也就是等待一段時(shí)間 )推入數(shù)組中。
這里我們使用了 Promise 來實(shí)現(xiàn)異步操作,在指定時(shí)間后 resolve 這個(gè) Promise。
最后它也返回自身。
function wait(duration) {
tasks.push(
() =>
new Promise((resolve) => {
setTimeout(resolve, duration * 1000);
})
);
return this;
}接著是 waitFirst 方法,它跟 wait 方法類似,只不過它把等待時(shí)間作為第一個(gè)任務(wù)插入到數(shù)組中。
所以我們使用了數(shù)組的 unshift 方法來實(shí)現(xiàn)。
function waitFirst(duration) {
tasks.unshift(
() =>
new Promise((resolve) => {
setTimeout(resolve, duration * 1000);
})
);
return this;
}最后是 execute 方法,它沒有參數(shù),也沒有返回值。
它負(fù)責(zé)遍歷數(shù)組中所有的任務(wù),并依次執(zhí)行它們。
因?yàn)橛行┤蝿?wù)是異步的(比如等待時(shí)間),所以我們使用了 async/await 的語(yǔ)法來保證執(zhí)行順序。
async function execute() {
for (const t of tasks) {
await t();
}
}至此我們已經(jīng)完成了所有代碼。
完整代碼如下:
function arrange(taskId) {
const tasks = [];
tasks.push(() => {
console.log(`${taskId} is notified`);
});
async function execute() {
for (const t of tasks) {
await t();
}
}
function doSomething(something) {
tasks.push(() => {
console.log(`Start to ${something}`);
});
return this;
}
function wait(duration) {
tasks.push(
() =>
new Promise((resolve) => {
setTimeout(resolve, duration * 1000);
})
);
return this;
}
function waitFirst(duration) {
tasks.unshift(
() =>
new Promise((resolve) => {
setTimeout(resolve, duration * 1000);
})
);
return this;
}
return {
execute,
do: doSomething,
wait,
waitFirst,
};
}
arrange("Tom").wait(2).do("abc").do("bcd").execute();
可以看到,任務(wù)的執(zhí)行已經(jīng)按照我們的預(yù)期完成啦。
總結(jié)
通過這篇文章,我們學(xué)習(xí)了如何實(shí)現(xiàn)一個(gè)可進(jìn)行時(shí)間和工作調(diào)度的任務(wù)管理器,它可以讓我們對(duì)一系列的任務(wù)進(jìn)行組織和執(zhí)行,讓我們的代碼更加智能和高效。
我們主要利用了鏈?zhǔn)秸{(diào)用和異步編程的方式,以及 Promise 和 async/await 的語(yǔ)法,來實(shí)現(xiàn)同步和異步的任務(wù)調(diào)度。
這是一個(gè)很好的面試題,也是一個(gè)很有用的技能。
在未來的開發(fā)中,類似這樣的任務(wù)調(diào)度器會(huì)經(jīng)常用到,特別是在需要按照一定順序執(zhí)行一系列異步操作的場(chǎng)景下,比如批量上傳文件、批量下載數(shù)據(jù)等。
掌握了這種任務(wù)調(diào)度器的實(shí)現(xiàn)方式,我們可以更加高效地完成復(fù)雜的異步編程任務(wù),提升我們的開發(fā)效率和代碼質(zhì)量。
到此這篇關(guān)于利用js實(shí)現(xiàn)可進(jìn)行時(shí)間和工作調(diào)度的任務(wù)管理器的文章就介紹到這了,更多相關(guān)js任務(wù)管理器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
屏蔽網(wǎng)頁(yè)右鍵復(fù)制和ctrl+c復(fù)制的js代碼
解決的方法就是直接把網(wǎng)頁(yè)保存下來然后刪掉下面這段js代碼,然后就可以正常用右鍵菜單,也可以通過設(shè)置瀏覽器的安全級(jí)別到最高級(jí)別來解決問題2013-01-01
javascript中節(jié)點(diǎn)的最近的相關(guān)節(jié)點(diǎn)訪問方法
parentNode——父節(jié)點(diǎn);firstChild——第一個(gè)子節(jié)點(diǎn);lastChild——最后一個(gè)子節(jié)點(diǎn);previousSibling——緊挨著的前面的兄弟節(jié)點(diǎn);這樣就可以作短途旅行,訪問當(dāng)前節(jié)點(diǎn)的某些相關(guān)節(jié)點(diǎn),感興趣的你可以參考下哈2013-03-03
原生js通過一行代碼實(shí)現(xiàn)簡(jiǎn)易輪播圖
這篇文章主要介紹了原生js一行代碼實(shí)現(xiàn)簡(jiǎn)易輪播圖功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-06-06
uniapp項(xiàng)目使用防抖及節(jié)流的方案實(shí)戰(zhàn)
防抖就是指觸發(fā)事件后把觸發(fā)非常頻繁的事件合并成一次去執(zhí)行,節(jié)流是指頻繁觸發(fā)事件時(shí)只會(huì)在指定的時(shí)間段內(nèi)執(zhí)行事件回調(diào),即觸發(fā)事件間隔大于等于指定的時(shí)間才會(huì)執(zhí)行回調(diào)函數(shù),這篇文章主要給大家介紹了關(guān)于uniapp項(xiàng)目使用防抖及節(jié)流的相關(guān)資料,需要的朋友可以參考下2023-01-01
JS動(dòng)態(tài)添加Table的TR,TD實(shí)現(xiàn)方法
這篇文章主要介紹了JS動(dòng)態(tài)添加Table的TR,TD實(shí)現(xiàn)方法,涉及js針對(duì)Table中TR、TD節(jié)點(diǎn)的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
Array.prototype.slice 使用擴(kuò)展
slice 可以用來獲取數(shù)組片段,它返回新數(shù)組,不會(huì)修改原數(shù)組。2010-06-06

