你真的懂异步嘛

233 阅读2分钟

1.同步与异步

  • 同步:等待结果
  • 异步:不等待结果
  • 异步常常伴随回调一起出现,但是异步不是回调,回调也不一定是异步。
// 同步的 sleep
function sleep(seconds){
    var start = new Date()
    while(new Date() - start < seconds * 1000){
        // 不满足条件不停执行
    }
    return
}
console.log(1)
sleep(3)
console.log('wake up')
console.log(2)
  • 控制台->performance->ESC->代码粘贴console->左上角圈圈
//异步的 sleep
function sleep(seconds, fn){
    setTimeout(fn, seconds * 1000)
}
console.log(1)
sleep(3, ()=> console.log('wake up'))
console.log(2)

  • 可以看出,用了异步之后,JS 的空闲时间,多了许多。
  • 但是注意,在 JS 空闲的这段时间,实际上是浏览器中的计时器在工作(很有可能是每过一段时间检查是否时间到了,具体要看 Chrome 代码)

2.几个典型的异步

2.1 图片加载异步(onload)

  • 图片加载过程是异步的
  • image加载完成才会触发onload
// 图片异步加载,现在宽度为 0,有缓存除外
document.getElementsByTagNames('img')[0].width   // 0
console.log('done')
document.getElementsByTagNames('img')[0].onload = function(){
    console.log(this.width) // 宽度不为 0
    console.log('real done')
}
console.log('done')

2.2 典型例子(onclick异步)

let liList = document.querySelectorAll('li')
for(var i=0; i<liList.length; i++){
    liList[i].onclick = function(){
        console.log(i)
    }
}
  • onclick时候i是几就打印几
  • 变量会提升 var i 会放for上面,i是贯穿循环的一个变量
  • var定义,3ms就已经变成了5
  • 结合词法树分析,i来源确定,但是值需要触发时确定
  • var i 改成 let 就可以解决

2.3 AJAX中的异步(success)

// 请求=>等=>响应打印(同步)
let request = $.ajax({
  url: '.',
  async: false  // 同步
})
console.log(request.responseText)
$.ajax({
    url: '/',
    async: true,  // 异步
    // 返回结果再触发
    success: function(responseText){
        console.log(responseText)
    }
})
console.log('先执行')

3.获取异步结果

3.1异步的形式

  • 一般有两种方法拿到异步结果
    • 轮询
    • 回调

3.2回调的形式

3.2.1 Node.js 的 error-first 形式
 fs.readFile('./1.txt', (error, content)=>{
     if(error){
         // 失败
     }else{
         // 成功
     }
 })
3.2.2 jQuery 的 success / error 形式
 $.ajax({
     url:'/xxx',
     success:()=>{},
     error: ()=>{}
 })
3.2.3 jQuery 的 done / fail / always 形式
 $.ajax({
     url:'/xxx',
 }).done( ()=>{} ).fail( ()=>{} ).always( ()=> {})
3.2.4 Prosmise 的 then 形式
 $.ajax({
     url:'/xxx',
 }).then( ()=>{}, ()=>{} ).then( ()=>{})
  • Promise返回一个then对象 接收一个成功函数 一个失败函数
  • 对函数回调形式的规范

4. 如何处理异常

    1. 如何使用多个success函数
    • 上一个then的return,下一个then接
    1. 有多个成功回调的情况下,如何处理异常
    • 有传错误处理reason就接,没有传,就最后catch
    • catch是语法糖,then(undefined, x=> {console.log('fail->', x)})
axios({
  url: '',
  async: true,
}).then(x => {
  console.log('成功')
  return Promise.reject('reject 111')
}, y => {
  console.log('失败')
}).then(x => {
  console.log('成功2')
}).catch(reason => {
  console.log('err=>', reason)
})

5. Promise/async/await

function ajax(){
    return new Promise((resolve, reject)=>{
        做事
        如果成功就调用 resolve
        如果失败就调用 reject
    })
}

var promise = ajax()
promise.then(successFn, errorFn)