# 1. js 开发总结

# 1.1. await 需要单独一行

let count = 0
async function fetchCount(id: number): Promise<number> {
  return id
}

async function addCount(id: number): Promise<void> {
  count = count + (await fetchCount(id)) //  错误示范count为300
  /* 正确示范,count为400
  const res = await fetchCount(id)
  count += res
  */
}
console.log('Home component mounted')
addCount(100)
addCount(300)

setTimeout(() => {
  console.log('count:', count)
}, 1100)

# 1.2. 正确捕获一个函数是否是同步还是异步错误

function fetchData() {
  const randomValue = Math.random()
  console.log('随机数:', randomValue)
  if (randomValue < 0.5) {
    throw new Error('同步错误')
  }
  if (randomValue > 0.5) {
    return Promise.reject(new Error('异步错误'))
  }
  return Promise.resolve('数据')
}
  • 1.2.1
try {
  fetchData()
    .then(data => {
      console.log('数据获取成功:', data)
    })
    .catch(error => {
      console.error('捕获到异步错误', error)
    })
} catch (error) {
  console.error('捕获到错误2:', error)
}
  • 1.2.2 Promise.try 能达到上面功能,但是需要 Node ≥ 22
Promise.try(fetchData)
  .then(data => {
    console.log('数据获取成功:', data)
  })
  .catch(error => {
    console.error('捕获到错误:', error)
  })
  • 1.2.3 安装 polyfill(保持老版本)
// npm i promise-try
const PromiseTry = require('promise-try')
PromiseTry(fn) // 等同于 Promise.try(fn)

# 1.3. 正则验证的莫名奇妙问题

  • 1.3.1 如下验证,会引发莫名奇妙的问题
const reg = /^[a-zA-Z0-9]+$/
function validate() {
  if (reg.test(this.value)) {
    console.log('合法')
  }
}
  • 1.3.2 解决方法 1,将正则放在局部,不用全局变量;这种方法不推荐
function validate() {
  const reg = /^[a-zA-Z0-9]+$/
  if (reg.test(this.value)) {
    console.log('合法')
  }
}
  • 1.3.3 解决方法 2,将正则.test()单独一行,不放在 if 语句块内;这种方法推荐
function validate() {
  const reg = /^[a-zA-Z0-9]+$/
  const result = reg.test(this.value)
  if (result) {
    console.log('合法')
  }
}
  • 1.3.4 解决方法 3,将正则.test()单独一行,重置 lastIndex 属性,避免影响下一次验证,这种方法推荐
function validate() {
  const reg = /^[a-zA-Z0-9]+$/
  reg.lastIndex = 0 // 重置 lastIndex 属性,避免影响下一次验证
  if (reg.test(this.value)) {
    console.log('合法')
  }
}

# 1.4. 回调处理

getUserInfo().then((userInfo)=> {
  getArticles(userInfo).then((articles)=>
    Promise.all(articles.map(getArticleDetail).then(console.log));
  })
})

// 上面简写
getUserInfo().then(getArticles).then((articles)=>{
  Promise.all(articles.map(getArticleDetail).then(console.log));
})

# 1.5. 异步递归(Promise.then)为何不会栈溢出?

Promise.then 是微任务,会将回调函数(foo)放入事件队列,当前调用栈执行完毕后才会执行。 每次递归调用时,foo 会立即返回,不会在调用栈中累积。新的 foo 调用会在下一个事件循环中异步执行,因此调用栈始终保持清空状态。

  • 5.1 Promise.then 将 foo 放入微任务队列,当前 foo 函数返回,调用栈清空。
  • 5.2 主线程空闲时,从微任务队列取出 foo 执行
function foo() {
  Promise.resolve().then(foo) //不会栈溢出,但是时间久了还是会卡死,慎用
  /* setTimeout(() => {}, 0)
  foo() */ //会栈溢出
}
foo()

# 1.6. 如何禁止别人调试自己的前端代码?

# 1.6.1. 无限 debugger

/**
 * 基础禁止调试代码
 */
;(() => {
  function ban() {
    setInterval(() => {
      debugger
    }, 50)
  }
  try {
    ban()
  } catch (err) {}
})()

# 1.6.2. 禁止断点的对策

;(() => {
  function ban() {
    setInterval(() => {
      debugger
    }, 50)
  }
  try {
    ban()
  } catch (err) {}
})()

# 1.6.3. 忽略执行的代码

// 加密前
;(() => {
  function ban() {
    setInterval(() => {
      Function('debugger')()
    }, 50)
  }
  try {
    ban()
  } catch (err) {}
})()

// 加密后
eval(
  (function (c, g, a, b, d, e) {
    d = String
    if (!''.replace(/^/, String)) {
      for (; a--; ) e[a] = b[a] || a
      b = [
        function (f) {
          return e[f]
        }
      ]
      d = function () {
        return 'w+'
      }
      a = 1
    }
    for (; a--; )
      b[a] && (c = c.replace(new RegExp('\b' + d(a) + '\b', 'g'), b[a]))
    return c
  })(
    '(()=>{1 0(){2(()=>{3("4")()},5)}6{0()}7(8){}})();',
    9,
    9,
    'block function setInterval Function debugger 50 try catch err'.split(' '),
    0,
    {}
  )
)

# 1.6.4. 终极增强防调试

;(() => {
  function block() {
    if (
      window.outerHeight - window.innerHeight > 200 ||
      window.outerWidth - window.innerWidth > 200
    ) {
      document.body.innerHTML = '检测到非法调试,请关闭后刷新重试!'
    }
    setInterval(() => {
      ;(function () {
        return false
      })
        ['constructor']('debugger')
        ['call']()
    }, 50)
  }
  try {
    block()
  } catch (err) {}
})()

# 1.6.5. 其他防调试技术

// 禁止右键菜单
document.oncontextmenu = function () {
  return false
}

// 禁止F12快捷键
document.onkeydown = function (e) {
  if (e.keyCode === 123) {
    return false
  }
}

// 禁止复制
document.oncopy = function () {
  return false
}

// 禁止粘贴
document.onpaste = function () {
  return false
}

// 检测开发者工具是否打开
setInterval(function () {
  if (typeof console.clear !== 'undefined') {
    location.reload()
  }
}, 1000)

css 开发总结

# 1.7. 模特换装