简单认识异步与Promise

307 阅读3分钟

什么是异步/同步

简单的来说,我们可以通过 是否能直接拿到结果 来判断是否为异步。

如果为同步,那么就必须等该代码执行完毕后在执行后面的代码。

如果为异步,那么就可以同时去执行其他代码。、


如何判断同步/异步

简单的来说,如果一个函数的返回值处于

  1. setTimeout
  2. AJAX(即XMLHttpRequest)
  3. addEventListener

那么,这个函数就是异步函数。

注意:ajax可以将其设置为同步,但如果设置为同步,会造成请求期间,整个页面卡住,因为同步操作必须等ajax请求完之后再执行后面的代码。


什么是回调

回调函数就是给别人调用的函数。

function f1(){}

function f2(fn){
    fn()
}

f2(f1)
//这f1是一个回调函数,因为他是给f2调用的,而不是给我调用的

异步与回调的关系

异步与回调是合作关系,而非附属关系。

array.forEach( item => console.log(item) )
//例如,此时,回调就被用于同步操作了,所以,回调不一样要用于异步操作。

在执行异步操作时,我们可以给他一个回调函数,这样,当异步操作完成时,就能将其结果作为参数传给回调函数了。


异步与回调总结

function 摇色子(){
    setTimeout(()=>{
        return parseInt( Math.random() * 6) + 1
    },1000)
    return udnefined
}

上面就是一个异步操作,1s之后,才会得到结果。

function 摇色子(){
    let result
    setTimeout(()=>{
        result = parseInt( Math.random() * 6) + 1
    },1000)
    return result
}

所以,正常情况下我们是无法得到result的。

此时,我们就需要一个回调函数了

function f1 (n){
    console.log(n)
}

function 摇色子(fn){
    setTimeout(()=>{
        fn( parseInt( Math.random() * 6) + 1)
    },1000)
    return undefined
}

上面的代码中,f1只用到了一次,所以我们可以将其简化为一个匿名函数

function 摇色子(fn){
    setTimeout(()=>{
        fn( parseInt( Math.random() * 6) + 1)
    },1000)
    return undefined
}

摇色子(console.log)

Promise

上面,我们提到了,如果使用回调,我们就可以对异步操作的结果进行处理,但,如果异步任务有两个结果(例如成功/失败)呢?

我们可能会想到两个解决方法:

  1. 回调接受两个参数
  2. 使用两个回调

但上面两种方法有一些缺点:

  1. 不规范,名称五花八门(success+fail,success+error,done+fail)
  2. 容易出现回调地狱,使代码难以看懂
  3. 很难进行错误处理

所以,为了解决上面的问题,人们提出了Promise。

下面,使用AJAX的简单封装举例。

function ajax (menthod,url,options){
    const {success,fail} = options
    const request = new XMLHttpRequest()
    request.open(menthod,url)
    request.onreadystatechange = () =>{
      if(request.readyState === 4){
          if (request.status >= 200 &&
              request.status < 300
              ){
                  success.call(null,request.response)
              }else {
                  fail.call(null,request)
              }
      }    
    }
    request.send()
}

ajax('GET','/xxx',{
    success(response){},
    fail : (request)=>{}
})

我们可以看到,上面的代码不够简洁,如果我们使用Promise

ajax = (method, url) => {
  return new Promise((resolve, reject) => {
    const request = new XMLHttpRequest();
    request.open(method, url);
    request.onreadystatechange = () => {
      if (request.readyState === 4) {
        if (request.status < 400) {
          resolve(request.response);
        } else if (request.status >= 400) {
          reject(request);
        }
      }
    };
    request.send();
  });
};


ajax('GET','/xxx')
  .then( (response)=>{} ,(request)=>{} )