Notes

TypeScript

既然刚刚在 Notes 里写了个面试题,忍不住怀念一下自己的第一次面试(which 挂了)。

当时没写出来(确实菜),虽然场下不紧张了马上就写出来了。

题目: 实现一个 LazyMan

  • LazyMan('Hank') 输出:

    Hi! This is Hank!
  • 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~
  • LazyMan('Hank').sleepFirst(5).eat('supper') 输出

    // 等待 5 秒
    Wake up after 5
    Hi This is Hank!
    Eat supper~
题解

现在无比丝滑的就做出来了,反而很难想象当时为什么没写出来。

function LazyMan(name: string) {
  const jobs: (
    | { type: "sleep"; time: number }
    | { type: "eat"; what: string }
    | { type: "say"; what: string }
  )[] = [
    {
      type: "say",
      what: `Hi! This is ${name}!`,
    },
  ];

  function sleepFirst(this: ReturnType<typeof LazyMan>, time: number) {
    jobs.unshift({
      type: "sleep",
      time,
    });
    return this;
  }

  function eat(this: ReturnType<typeof LazyMan>, what: string) {
    jobs.push({
      type: "eat",
      what,
    });
    return this;
  }

  function sleep(this: ReturnType<typeof LazyMan>, time: number) {
    jobs.push({
      type: "sleep",
      time,
    });
    return this;
  }

  setTimeout(async () => {
    for (const job of jobs) {
      switch (job.type) {
        case "say":
          console.log(job.what);
          break;
        case "sleep":
          await new Promise((r) => setTimeout(r, job.time * 1000));
          console.log(`Wake up after ${job.time}`);
          break;
        case "eat":
          console.log(`Eat ${job.what}~`);
          break;
      }
    }
  }, 0);

  return {
    sleep,
    sleepFirst,
    eat,
  };
}

// LazyMan('Hank');
// LazyMan('Hank').sleep(10).eat('dinner');
// LazyMan('Hank').eat('dinner').eat('supper');
// LazyMan("Hank").sleepFirst(5).eat("supper");
TypeScript

偶然在小红书上刷到一个前端面试题,顺手做了一下。

要求:实现一个带并发限制的异步调度器 Scheduler,保证同时运行的异步任务最多 MAX_LENGTH 个,使得以下程序能正确输出

const timeout = (time) =>
  new Promise((resolve) => {
    setTimeout(resolve, time);
  });
const MAX_LENGTH = 2;
const scheduler = new Scheduler(MAX_LENGTH);
const addTask = (time, order) => {
  scheduler
    .add(() => {
      return timeout(time);
    })
    .then(() => console.log(order));
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");

//  output: 2 3 1 4
// 一开始,1、2两个任务进入队列
// 500ms时,2完成,输出2,任务3进队
// 800ms时,3完成,输出3,任务4进队
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4

感觉还是有点简单,五分钟内肯定是能做出来了。

题解

一开始漏了异常处理的情况,让 gpt 看了眼指了出来

class Scheduler {
  running = 0;
  pending_tasks: (() => void)[] = [];
  queue_len: number;

  constructor(queue_len: number) {
    this.queue_len = queue_len;
  }

  async add<T>(promiseCb: () => Promise<T>): Promise<T> {
    if (this.running >= this.queue_len) {
      await new Promise<void>((resolve) => {
        this.pending_tasks.push(resolve);
      });
    }
    this.running++;
    try {
      return await promiseCb();
    } catch (err) {
      throw err;
    } finally {
      const resolve = this.pending_tasks.shift();
      if (resolve) {
        resolve();
      }
      this.running--;
    }
  }
}

const scheduler = new Scheduler(2);

const sleepAndLog = (time: number, ...txt: unknown[]) =>
  new Promise((r) => setTimeout(r, time)).then(() => console.log(...txt));
const sleepAndRaiseLog = (time: number, ...txt: unknown[]) =>
  new Promise((r) => setTimeout(r, time)).then(() => Promise.reject(...txt));

scheduler.add(() => sleepAndLog(10000, "1"));
scheduler.add(() => sleepAndRaiseLog(5000, "2"));
scheduler.add(() => sleepAndLog(3000, "3"));
scheduler.add(() => sleepAndLog(4000, "4"));