-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
14. 实现一个 LazyMan & 升级实现每个都能返回自己的 then (即asyncQueue) #15
Labels
Comments
贴个自己完成的 重点有三个
function LazyMan(name) {
return new _LazyMan(name)
}
function _LazyMan(name) {
this.name = name;
this.queues = []
// 这里首先要执行的 hello
this.Hello()
// 这个 setTimeout 很重要,主要是为了 push 完 .sleepFirst/.eat 这些方法到队列中
setTimeout(() => {
this.exec()
})
}
_LazyMan.prototype.Hello = function() {
this.handler(() => {
console.log(`Hi This is ${this.name}!`)
})
return this;
}
_LazyMan.prototype.handler = function(fn, number = 0, before = false) {
const cur = () => setTimeout(() => {
fn()
this.exec()
}, number * 1000)
if (before) {
this.queues.unshift(cur)
} else {
this.queues.push(cur)
}
}
_LazyMan.prototype.exec = function(){
const fn = this.queues.shift()
fn?.()
}
_LazyMan.prototype.sleepFirst = function(time) {
this.handler(() => {}, time, true)
return this;
}
_LazyMan.prototype.eat = function(food) {
this.handler(() => {
console.log(`Eat ${food} !`)
})
return this;
} |
fedono
changed the title
14. 实现一个 LazyMan
14. 实现一个 LazyMan & 升级实现每个都能返回自己的 then (即asyncQueue)
Sep 13, 2023
class AutoQueue {
constructor() {
this.tasks = [];
this._pendingPromise = false;
}
enqueue(action) {
return new Promise((resolve, reject) => {
this.tasks.push({ action, resolve, reject });
this.dequeue();
});
}
async dequeue() {
// 这个的主要目的,就是当前有一个正在执行时,下一个 action 就不要执行,等着前一个执行完
if (this._pendingPromise) return false;
let item = this.tasks.shift();
if (!item) return false;
try {
this._pendingPromise = true;
let payload = await item.action(this);
this._pendingPromise = false;
item.resolve(payload);
} catch (e) {
this._pendingPromise = false;
item.reject(e);
} finally {
this.dequeue();
}
return true;
}
}
// Helper function for 'fake' tasks
// Returned Promise is wrapped! (tasks should not run right after initialization)
let _ =
({ ms, ...foo } = {}) =>
() =>
new Promise((resolve) => setTimeout(resolve, ms, foo));
// ... create some fake tasks
let p1 = _({ ms: 50, url: '❪𝟭❫', data: { w: 1 } });
let p2 = _({ ms: 20, url: '❪𝟮❫', data: { x: 2 } });
let p3 = _({ ms: 70, url: '❪𝟯❫', data: { y: 3 } });
let p4 = _({ ms: 30, url: '❪𝟰❫', data: { z: 4 } });
const aQueue = new AutoQueue();
const start = performance.now();
aQueue
.enqueue(p1)
.then(({ url, data }) => console.log('%s DONE %fms', url, performance.now() - start)); // = 50
aQueue
.enqueue(p2)
.then(({ url, data }) => console.log('%s DONE %fms', url, performance.now() - start)); // 50 + 20 = 70
aQueue
.enqueue(p3)
.then(({ url, data }) => console.log('%s DONE %fms', url, performance.now() - start)); // 70 + 70 = 140
aQueue
.enqueue(p4)
.then(({ url, data }) => console.log('%s DONE %fms', url, performance.now() - start)); // 140 + 30 = 170 |
贴一个实现的比较好的版本,不用 setTimeout,直接使用 Promise.resolve().then(fn) 的方式 const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))
/*
interface Laziness {
sleep: (time: number) => Laziness
sleepFirst: (time: number) => Laziness
eat: (food: string) => Laziness
}
*/
/**
* @param {string} name
* @param {(log: string) => void} logFn
* @returns {Laziness}
*/
function LazyMan(name, logFn) {
const cmds = [['greet', name]]
const actions = {
greet: name => logFn(`Hi, I'm ${name}.`),
eat: food => logFn(`Eat ${food}.`),
sleep: ms => sleep(ms * 1000).then(() => logFn(`Wake up after ${ms} second${ms > 1 ? 's' : ''}.`)),
}
Promise.resolve().then(exec)
async function exec() {
for (const [cmd, val] of cmds) {
await actions[cmd](val)
}
}
return {
sleep(ms) {
cmds.push(['sleep', ms])
return this
},
sleepFirst(ms) {
cmds.unshift(['sleep', ms])
return this
},
eat(food) {
cmds.push(['eat', food])
return this
},
}
} 来自 JavaScript Coding Questions / 130. create LazyMan() / Discuss |
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time * 1000)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
scheduler.add(() => timeout(time))
.then(() => console.log(order))
}
// 每次最多执行两个
addTask(1, 'jack1')
addTask(2, 'jack2')
addTask(3, 'jack3')
addTask(4, 'jack4') 解法和 asyncQueue 差不多 class Scheduler {
tasks = []
count = 0
add(promiseCreator) {
return new Promise((resolve, reject) => {
// 这一步非常之关键,需要将 resolve/reject 都添加进去,这样每个 add 后面的 then,其实都可以获取当前运行的结果
this.tasks.push([promiseCreator, resolve, reject])
this.exec()
})
}
async exec() {
if (this.tasks.length === 0) {
return
}
if (this.count >= 2) {
return;
}
this.count++
const [fn, resolve, reject] = this.tasks.shift()
try {
const res = await fn()
resolve(res)
} catch (error) {
reject(error)
} finally {
this.count--;
this.exec()
}
}
}
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
问题
实现一个LazyMan,可以按照以下方式调用:
解法
对于这个问题,首先创建一个任务队列,然后利用next()函数来控制任务的顺序执行:
参考
The text was updated successfully, but these errors were encountered: