經典鏈式呼叫 Person("Dan").sleep(2).eat("dinner")

Allan91發表於2023-04-24

實現:

// Person('Li')
/* 輸出:
Hi! This is Hank!
*/
// Person('Dan').sleep(3).eat('dinner')
/* 輸出:
Hi! This is Hank!
// 等待10秒..
Wake up after 10
Eat dinner~
*/
// Person('Jerry').eat('dinner~').eat('supper~')
/* 輸出:
Hi This is Hank!
Eat dinner~
Eat supper~
*/
Person('Smith').sleepFirst(2).eat('supper')
/* 等待5秒,輸出
Wake up after 5
Hi This is Hank!
Eat supper
*/
function Person(name) {
  return new CreatePerson(name)
}

class CreatePerson {
  constructor(name){
    this.tasks = [] // 核心,使用佇列(陣列)來儲存要執行的函式
    this.tasks.push(()=> console.log(`Hi! This is ${name}`))

    this.runTask()
  }

  runTask() {
    // 關鍵!利用宏任務將事件延遲執行
    // 如果遇到 sleepFirst,可以先將 sleepFirst 壓入任務佇列,然後按順序執行
    setTimeout(() => this.exector())
  }

  exector() {
    if(this.tasks.length === 0) return // 遞迴出口

    const task = this.tasks.shift() // 取出任務

    if(typeof task === "number") {
      setTimeout(() => {
        console.log(`Wake up after ${task}`)
        this.exector() // 遞迴自身
      }, 2000)
    }
    
    if (typeof task === 'function') {
      task()
      this.exector() // 遞迴自身
    }

    return this
  }

  // 維護各種任務,用任務佇列儲存
  eat(food) {
    this.tasks.push(() => console.log(`Eat ${food}~`)) // 常規操作,塞進任務佇列
    return this
  }

  sleep(time) {
    this.tasks.push(time) // 常規操作,塞進任務佇列
    return this
  }

  sleepFirst(time) {
    console.log(1);
    this.tasks.unshift(time) // 執行:塞進第一項!
    return this
  }
}

相關文章