目录
异步调度问题
题目一
1.实现一个带并发限制的异步调度Scheduler,保证同时运行的任务最多有N个。完善下面代码中的Scheduler类,使以下程序能正确输出
class Scheduler {
add(promiseCreator) {
}
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler(3)
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, 'a')
addTask(500, 'b')
addTask(100, 'c')
addTask(2000, 'd')
addTask(10, 'f')
答案
方法一
class Schdule {
constructor(n) {
this.max = max
this.count = 0
this.queue = []
}
async add(promiseCreator) {
if (this.count >= this.max) {
await new Promise((resolve, reject) => this.queue.push(resolve))
}
this.count++;
let res = await promiseCreator()
this.count--;
if (this.queue.length) {
this.queue.shift()()
}
return res
}
}
方法二
class Schdule {
constructor(n) {
this.max = max
this.count = 0
this.queue = []
}
add(promiseCreator) {
return new Promise(resolve => {
promiseCreator.resolve = resolve; // 保存当前promise的状态
if (this.count < this.max) { // 最大并发任务处理
this.runWork(promiseCreator)
} else {
this.queue.push(promiseCreator)
}
})
}
runWork(promiseCreator) {
this.count++
promiseCreator().then(() => {
promiseCreator.resolve()
this.count--
if (this.queue.length) {
this.runWork(this.queue.shift())
}
})
}
}
题目二
实现一个带并发限制的异步调度PromiseQueue,保证同时运行的任务最多有N个且按优先级运行任务。完善下面代码中的PromiseQueue类,使以下程序能正确输出
link1start
link2start
link3start
link2end
high prioritystart
link1end
link5start
link3end
link4start
high priorityend
link4end
link5end
const urls = [
{
info: 'link1',
time: 3000,
priority: 1
}, {
info: 'link2',
time: 2000,
priority: 2
}, {
info: 'link3',
time: 3000,
priority: 3
}, {
info: 'link4',
time: 2000,
priority: 2
}, {
info: 'link5',
time: 5000,
priority: 5
}
]
function loadImg(url) {
return new Promise((resolve, reject) => {
console.log(url.info + 'start')
setTimeout(() => {
console.log(url.info + 'end')
resolve()
}, url.time)
})
}
class PromiseQueue {
}
const q = new PromiseQueue({
concurrency: 3
})
const formatTask = (url) => {
return {
fn: () => loadImg(url),
priority: url.priority
}
}
urls.forEach(url => {
q.add(formatTask(url))
})
const highPriorityTask = {
priority: 10,
info: 'high priority',
time: 2000
}
q.add(formatTask(highPriorityTask))
答案
class PromiseQueue {
constructor(options = {}) {
this.concurrency = options.concurrency || 1;
this.currentCount = 0
this.pendingList = []
}
add(task) {
this.pendingList.push(task)
this.run()
}
run() {
if (this.pendingList.length === 0) {
return;
}
if (this.concurrency === this.currentCount) {
return;
}
this.currentCount++
const { fn } = this.pendingList.sort((a, b) => b.priority - a.priority).shift()
fn().then(this.completeOne.bind(this)).catch(this.completeOne.bind(this))
}
completeOne() {
this.currentCount--
this.run()
}
}
递归输出
题目一
实现compose函数使下面的代码输出顺序为1,2,3,3.3,2.2,1.1 。
let middleware = []
middleware.push((next)=>{
console.log(1)
next()
console.log(1.1)
})
middleware.push((next)=>{
console.log(2)
next()
console.log(2.2)
})
middleware.push((next)=>{
console.log(3)
next()
console.log(3.3)
})
let fn = compose(middleware)
fn()
这里观察输出1后执行next,然后输出2,执行next在到3,然后3.3,回到2.2,再回到1.1,这里明显为一个递归调用,传入的参数next为递归的函数,每次调用便会执行下一个函数。
答案
function compose(...args){
let index = 0;
return function fn() {
if(args[0].length<=index){
return;
}
return args[0][index++](fn)
}
}
function compose(middlewares) {
const copyMidlewares = [...middlewares];
let index = 0
const fn = () => {
if (index >= copyMidlewares.length) {
return ;
}
const middlewares = copyMidlewares[index];
index++;
return middlewares(fn)
}
return fn;
}
Promise相关
题目一
编写Promise.all和Promise.race方法。
答案
Promise.all = (arr) => {
if (!Array.isArray(arr)) {
return;
}
let counter = 0;
let result = []
return new Promise((resolve, reject) => {
arr.forEach((item, index) => {
Promise.resolve(item).then(value => {
result[index] = value;
counter++;
if (counter === arr.length) {
resolve(result);
}
}).catch(err => {
reject(err)
})
})
});
}
Promise.rRace = function (arr) {
if (!Array.isArray(arr)) {
return;
}
return new Promise((resolve, reject) => {
arr.forEach(v => {
Promise.resolve(v).then(value=>{
resolve(value)
}).catch(err => reject(err))
})
})
}
占用空间大小
题目一
1.计算一个变量占用的字节数(string占2字节,boolean占4字节,number占8字节)
注意
1.对象的属性值也占用字
2.相同的引用只能算一次
答案
const set = new Set()
function sizeOfObject(object) {
if (object == null) {
return 0
}
let bytes = 0;
const properties = Object.keys(object)
for (let i = 0; i < properties.length; i++) {
const key = properties[i]
if (typeof object[key] === 'object' && object[key] !== null) {
if (set.has(object[key])) {
bytes += calculator(key)
continue
}
set.add(object[key])
}
bytes += calculator(key)
bytes += calculator(object[key])
}
return bytes
}
function calculator(object) {
switch (typeof object) {
case 'string': {
return object.length * 2
}
case 'boolean': {
return 4
}
case 'number': {
return 8
}
case 'object': {
if (Array.isArray(object)) {
return object.map(calculator).reduce((res, current) => res + current, 0)
}
return sizeOfObject(object)
}
}
}
渲染虚拟节点
题目一
1.将如下数据格式的虚拟dom为真实dom
const vnode = {
tag: 'DIV',
attrs: {
id: 'app'
},
children: [
{
tag: 'SPAN',
children: [{
tag: 'A',
children: []
}]
},
{
tag:'SPAN',
children:[
{
tag:'A',
children:[]
},
{
tag:'',
children:[]
}
]
}
]
}
答案
function render(vnode){
if(typeof vnode === 'number'){
vnode = String(vnode)
}
if(typeof vnode=== 'string'){
return document.createTextNode(vnode);
}
const element = document.createElement(vnode.tag);
if(vnode.attrs){
Object.keys(vnode.attrs).forEach(key=>{
element.setAttribute(key,vnode.attrs[key])
})
}
if(vnode.children.length){
vnode.children.forEach(v=>{
element.appendChild(render(v))
})
}
return element
}
实现for of
题目一
如何使对象实现for of。
答案
方法一
obj[Symbol.iterator]=function(){
const _this = this
//也可使用: keys = Object.getOwnPropertyNames(this)
const keys = Object.keys(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}
方法二
obj[Symbol.iterator] = function *(){
for(let prop in this){
yield this[prop]
}
}