异步与promise

同步和异步

  • 同步:直接能拿到结果
  • 异步:不能直接拿到结果

判断一个函数是同步的还是异步

如果函数处于

  • setTimeout
  • AJAX
  • AddEventListener
    这三个内部,就是异步

回调

拿到异步函数的结果,可以通过轮询和回调

  • 轮询就是每过一段时间去查看拿到了没
  • 回调就是写了却不调用,回头给别人调用的函数

举例

  1. 把函数1给另一个函数2
function f1(){}
function f2(fn){
fn()
}
f2(f1)
  • 我没有调用f1
  • f1传给了f2
  • f2调用了f1
  • f1是我写给f2调用的函数
  • 所以f1是回调
  1. 摇骰子
function (){
    setTimeout(()=>{ 
        return parseInt(Math.random() * 6) + 1
    },1000)
// return undefined
}
  • 摇骰子()没有写return ,所以return undefined
  • 箭头函数里有return, 返回真正的结果
  • 所以这是一个异步函数
  • 如何拿到异步结果
function callback(x) {
    console.log(x)
}

摇骰子(callback){
    setTimeout(()=>{
    callback(parseInt(Math.random()*6) + 1)
  },1000)
}

简化为箭头函数

摇骰子(x=>{
console.log(x)
})

// 由于这里函数的参数和需要用到的值是一样的,所以还可以简化为
摇骰子(console.log)  

参数个数不一致不能这么简化

const array = ['1', '2', '3'].map(parseInt)
//得到的结果是 [1, NaN, NaN]

Map函数和parseInt函数参数不同导致的错误,该代码等价于

['1', '2', '3'].map((currentValue, index, array) => {
    parseInt(currentValue, index, array)
  // parseInt('1', 0) 把'1'换成0进制,那就是1
  // parseInt('2', 1) 把'2'换成1进制,1进制里没有2,所以是NaN
  // parseInt('3', 2) 把'3'换成2进制,2进制里没有3,所以是NaN
})

只要写明参数即可

['1', '2', '3'].map((currentValue, index, array) => {
    parseInt(currentValue)
}

小结

  • 异步任务不能拿到结果
  • 于是我们传一个回调给异步任务
  • 异步任务完成时调用回调函数
  • 调用的时候把结果作为参数

promise

回调地狱

如果异步任务有多个结果,在没有promise时,会出现回调地狱

getUser( user => {
    getGroups(user, (groups)=>{
        groups.forEach( (g)=>{
            g.filter(x => x.ownerId === user.id)
                .forEach(x => console.log(x))
        })
    })
})

而且这种写法还会有另外的问题

  • 回调函数命名缺乏规范, 每个程序员都有可能给回调函数起不同的名字
  • 不能很好地捕获错误

promise

使用promise的好处

  • 解决回调地狱,增强代码可读性
  • 规范回调的名字或顺序
  • 很方便地捕获错误
    以AJAX的封装为例
ajax = (method, url, options)=>{
    const {success, fail} = options 
    const request = new XMLHttpRequest()
    request.open(method, url)
    request.onreadystatechange = ()=>{
        if(request.readyState === 4){
        // success fail
            if(request.status < 400){
                success.call(null, request.response)
            }else if(request.status >= 400){
                fail.call(null, request, request.status)
            }
        }
    }
    request.send()
}
ajax('get', '/xxx', { 
    success(response){}, fail: (request, status)=>{}
})   //成功执行success,失败执行fail

可改写成

ajax = (method, url, options)=>{
    return new Promise((resolve, reject)=>{
        const {success, fail} = options
        const request = new XMLHttpRequest()
        request.open(method, url)
        request.onreadystatechange = ()=>{
            if(request.readyState === 4){
            // 成功resolve,失败 reject
                if(request.status < 400){
                    resolve.call(null, request.response)
                }else if(request.status >= 400){
                    reject.call(null, request)
                }
            }
        }
        request.send()
    })
}

小结

  1. 第一步
  • return newPromise((resolve,reject)=>{...})
  • 任务成功调用resolve(result)
  • 任务失败调用reject(error)
  • resolve和reject会再去调用成功和失败函数
  1. 第二步
  • 使用.then(success,fail)传入成功和失败函数

你可能感兴趣的:(异步与promise)