JavaScript知识

136 阅读2分钟

并发控制

class Concurrent {
  constructor(limit) {
    this.limit = limit
    this.running = 0
    this.queue = []
  }

  run (fn, ...args) {
    return new Promise((resolve, reject) => {
      const task = () => {
        this.running++
        fn(...args).then(resolve).catch(reject).finally(() => {
          this.running--
          if (this.queue.length) {
            this.queue.shift()()
          }
        })
      }
      if (this.running < this.limit) {
        task()
      } else {
        this.queue.push(task)
      }
    })
  }
}

const concurrent = new Concurrent(3)
const p = (t) => {
  console.log('开始运行', t)
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('结束', t)
      resolve(t)
    }, t)
  })
}

Promise.all([
  concurrent.run(p, 4000),
  concurrent.run(p, 401),
  concurrent.run(p, 500),
  concurrent.run(p, 501),
  concurrent.run(p, 502),
  concurrent.run(p, 503),
  concurrent.run(p, 504),
  concurrent.run(p, 505),
])
  .then((res) => {
    console.log(res, 'done')
  })
  .catch((error) => {
    console.error('Error:', error)
  })

// 开始运行 4000
// 开始运行 401
// 开始运行 500
// 结束 401
// 开始运行 501
// 结束 500
// 开始运行 502
// 结束 501
// 开始运行 503
// 结束 502
// 开始运行 504
// 结束 503
// 开始运行 505
// 结束 504
// 结束 505
// 结束 4000
// [4000, 401, 500,501, 502, 503,504, 505] done

call和apply方法

callapply是用于绑定this指向的,他们就是参数不同,作用基本相同。

  1. 每个函数都包含两个非继承而来的方法:apply()call()
  2. 他们的用途相同,都是在特定的作用域中调用函数。
  3. 接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
  4. call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。

手写Bind

function fn1(a,b,c) {
  console.log("this", this, "参数", a, b, c);
  return "this fn1"
}
// 原生bind
const fn2 = fn1.bind({t: "指定的this"})
fn2(1,2,3) // 输出: this { t: '指定的this' } 参数 1 2 3

// 手动实现的bind
Function.prototype.bind2 = function (context) {
  context = typeof context === "object" ? (context || widnow) : window
  return (...args) => {
    this.call(context, ...args)
  }
}
const fn3 = fn1.bind2({t: "指定的this - 3"})
fn3(2,2,4) // 输出: this { t: '指定的this - 3' } 参数 2 2 4

手写call

function f1(a, v) {
  console.log("this", this, "参数", a, v);
}
Function.prototype.call2 = function (context) {
  context = typeof context === "object" ? (context || widnow) : window
  const args = arguments[1] //获取传入的数组参数
  const key = Symbol()
  context[key] = this
  const res = context[key](...arg)
  delete context[key]
  return res
}
const context = {t: "指定的this - call"}
f1.call2(context, 1,2)
console.log(context);
/* 输出
this { t: '指定的this - call', fn: [Function: f1] } 参数 1 2
{ t: '指定的this - call' }
*/

实现new

function Man(options) {
  this.age = options.age
  this.name = options.name
  Man.prototype.work = "nonw"
}
// 原生 new
const m = new Man({name: "原生new", age: 0})

// 手写new
function myNew (context, ...args) {
  const obj = {}
  obj.__proto__ = context.prototype
  context.call(obj, ...args)
  return obj
}

const s = myNew(Man, {name: "my new", age: 1})
console.log(m, s);
// 输出 Man { age: 0, name: '原生new' } Man { age: 1, name: 'my new' }

Event Bus

class EventBus {
  constructor() {
    this.map = {}
  }
  on(type, fn) {
    this.map[type] = (this.map[type] || []).concat(fn)
  }
  emit(type, ...args) {
    if (this.map[type]) {
      this.map[type].forEach(f => {
        f(...args)
      });
    }
  }
  off(type, fn) {
    if (this.map[type]) {
      if (fn) {
        const index = this.map[type].indexOf(fn)
        index > -1 && this.map[type].splice(index, 1)
      } else {
        delete this.map[type]
      }
    }
  }
}

发布、订阅

class Subject {
  constructor() {
    this.observes = []
  }
  addObserves(observe) {
    this.observes.push(observe)
  }
  delObserve(observe) {
    const index = this.observes.indexOf(observe)
    index > -1 && this.observes.splice(index, 1)
  }
  update() {
    this.observes.forEach(o => {
      o.update()
    })
  }
}
class Observe {
  update() {
    // do something
  }
  subscribeTo(subject) {
    subject.addObserves(this)
  }
}