异步与Promise

147 阅读3分钟

异步与同步

同步:能直接拿到结果的。就比如说你在医院挂号,你要拿到号才会离开。同步任务可能消耗几毫秒到几十毫秒不等,总之是要拿到结果才行。

异步:不能直接拿到结果的。就比如说你在餐厅等号,拿到号你可以临时离开去干别的事,你可以每隔一段时间来问一下(轮询),也可以通过手机来得到消息(回调)。

回调(callback)

写给别人用的函数就是回调。假设request.onreadystatechange就是写给浏览器调用的,意思就是浏览器回头调用一下这个函数。写了却不调用,给别人调用的函数,就是回调。

function f1(){}
function f2(fn){
  fn()
}
f2(f1)   

上述是把f1传给了f2,f2调用了f1,没有调用f1,所以f1是写给f2调用的函数,即f1就是回调。

异步与回调(callback)的关系

  • 异步任务需要用到回调函数来通知结果。
  • 但是回调函数不一定只用在异步任务里面,回调可以用到同步任务里array.forEach(n=>console.log(n))就是同步回调。
  • 异步常常会用到回调,但不一定要用到回调。异步不只有回调,还有轮询。

判断异步与同步

异步:

setTimeout
AJAX(即XMLHttpRequest)
AddEventListener

虽然AJAX也可以同步,但是不要将AJAX设置为同步的,因为将AJAC设置为同步,这样做会使请求期间页面卡住。

举个异步的例子:

function yao(){
    setTimeout(()=>{
        return parseInt(Math.random() * 6)+1
    },1000)
}

分析:yao()没有return,箭头函数里面有return,这里返回的才是真正的结果, 这里的箭头函数现在并没有被立即执行,所以这是一个异步任务/函数。

yao()返回的是一个undefine值,那么我们要怎么样才能获取到异步结果呢? 我们可以利用回调,写一个函数,然后把这个函数地址给它,

function yao(fn){
    setTimeout(()=>{
        fn(parseInt(Math.random()*6)+1))
    },1000)
}
yao(console.log)  //function f1(x){console.log(x)};   yao(f1)的缩写

两个异步结果

在AJAX中,我们回遇到成功和失败的两个异步任务结果,我们可以用以下两种方法

方法一,回调接受两个参数,一个是成功参数,一个是失败参数。

fs.readFile('/1.txt', (error, data)=>{
  if(error){console.log('失败');return}
  console.log(data.toString()) //成功
})

方法二:写两个回调

//参数传
ajax('get', '1.json', (data)=>{}, (error)=>{})

//或者对象传:
ajax('get', '1.json',{
     	success: ()=>{},
  	fail: ()=>{}
	}
}

但是这两个方法有缺陷:

  • 不规范,有人用success+error,有人用success+fail,有人用done+fail。
  • 容易出现回调地狱,代码看不懂
  • 很难进行错误处理

Promise

为了解决上述的三个问题,Promise出现了。

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

Promise创建方法

new Promise((resolve,reject) =>{
    resolve(result)    //任务成功则调用resolve(result)
    reject(error)      //任务失败则调用reject(error)
})

Promise使用方法

ajax = (method,url,options)=>{
    return new Promise((resolve,reject)=>{
        const {success,fail} = options    //析构赋值,const sucess= options.success  const fail = options.fail
        const request = new XMLHttpRequest()
        request.open(method,url)
        request.onreadystatechange = ()=>{
            if(request.readyState ===4){
              if(request.status<400){
                  resolve.call(null,request.response)
              }else {
                  reject.call(null,request)
            }
           }
        }
        request.send()
    })
}
ajax('get','/xxx').then(
    (response)=>{},       //成功回调函数,只传一个参数
    (request)=>{}         //失败回调函数,只传一个参数
)

Promise总结

  1. return new Promise((resolve,reject)=>{…})
  2. 任务成功调用resolve(result),任务失败调用reject(error)
  3. resolve和reject会再去调用成功和失败函数
  4. 使用.then(success,fail)传入成功和失败函数