异步编程

6 阅读7分钟

同步与异步?

  1. 同步:后一个任务等待前一个任务执行完毕后再执行
  2. 异步:非阻塞的,主逻辑与异步逻辑相互独立,主逻辑不需要等待异步逻辑完成,而是可以立即执行下去

事件循环?

  1. JS中用来存储待执行回调函数的队列包含2个不同特定的列队
  2. 宏任务队列:用来保存待执行的宏任务(回调)比如:定时器回调/DOM事件回调/ajax回调;
  3. 微任务队列:用来保存待执行的微任务(回调)比如:promise回调/MutationObserver回调/process.nextTick;
  4. 事件循环?执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。

异步编程的实现方式?

  1. 回调函数:多个回调函数嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦合度太高,不利于代码的可维护
  2. Promise 的方式:使用 Promise 的方式可以将嵌套的回调函数作为链式调用。但是使用这种方法,有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确。
  3. generator 的方式:在 generator 内部对于异步操作的方式,可以以同步的顺序来书写,yield表达式可以暂停函数执行,next方法用于恢复函数执行,这使得Generator函数非常适合将异步任务同步化
  4. async 函数:可以将异步逻辑,转化为同步的顺序来书写,并且这个函数可以自动执行。本质是generatorpromise实现的一个自动执行的语法糖,它内部自带执行器。

Promise 对象?

  1. 是异步编程的一种解决方法,它是一个构造函数,由它的实例对象来封装一个异步操作,并且可以获取其成功或失败的结果。
  2. 构造函数Promise内部自动执行一个执行器函数,执行器函数接收两个参数resolve、reject两个回调函数,executor执行器函数是同步回调函数。
  3. 有三个状态:pending、fulfilled、rejected。实例的状态只能由pending变fulfilled或者pending变rejected状态,并且状态一经改变,就没办法再被改变了。
  4. 状态如何改变的呢?通过resolve()函数将状态改为fulfilledreject()函数将状态改为rejected
  5. 解决回调地狱:回调函数嵌套使用,不利于阅读以及异常处理。Promise的链式调用解决了回调地狱。它实例对象具有then和catch方法,而它们的返回结果依然是一个Promise对象,因此可以使用.符号进行链式调用。
//创建一个新的promise
let p = new Promise((resolve,reject)=>{
  // 成功后调用resolve(),这时promise状态由pending变为fulfilled,返回一个新的Promise
  // 成功后调用reject(),这时promise状态由pending变为rejected, 返回一个新的Promise
})
p.then(
  (value)=>{}, //接收到成功的value数据
  (reason)=>{} //接收到失败的reason数据
)

async/await?

  1. async函数,这个函数就是纯同步执行,不过返回值为promise对象
  2. await表达式:① 返回值如果表达式是promise对象,await返回的是promise成功的值;如果表达式是其它值,直接将此值作为await的返回值。
  3. await此行代码之后的语句一起作为整体变为微队列中的异步回调。相当于给后面的代码套了一层 then 方法。
  4. 如果await的promise失败了,就会抛出异常,需要通过 try..catch 捕获处理
  5. 真正起作用的是await,可以把async关键字简单的当作一个 标识符. 因为如果异步函数中不使用 await关键字,除了返回值为promise对象,其执行基本上跟普通函数没有什么区别。

XHR请求

  1. 全称是XMLHttprequest,用于与服务器进行交互,通过它可以在不刷新页面的情况下请求特定的url,获取数据。所以可以在不影响用户操作的情况下,更新页面的局部内容。
  2. 语法

a. XMLHttpRequest(): 创建XHR对象的构造函数
b. open(): 初始化一个请求, 参数为: (method, url[, async])
c. send(data): 发送请求 abort(): 中断请求
d. setRequestHeader(name, value): 设置请求头
e. onreadystatechange(): 绑定readyState改变的监听。0初始 1open()之后 2send()之后 3请求中 4请求完成

// 1 手写ajax
// 1. 创建XHR实例,let xhr = new XMLHttpRequest() 
// 2. 配置请求:xhr.open('GET', url)
// 3. 发去请求: xhr.send()
// 4. 获取请求状态 onreadystatechange() = function(){ xhr.readyState xhr.status xhr.responseText}
let ajax = function(url){
  return new Promise((resolve, reject)=>{
    //创建XHR对象的实例
    let xhr = new XMLHttpRequest()
    // 初始化请求
    xhr.open('GET', url, true)
    //设置请求头
    xhr.setRequestHeader('Content-Type', 'application/json')
    // 绑定回调函数:onreadystatechange(),监听readyState的改变
    xhr.onreadystatechange = function(){
      //readyState:4请求完成后再判断状态码status
      if(xhr.readystate !== 4) return;
      if(xhr.status >= 200 || xhr.status < 300){
        //请求成功调用resolve(responseData)
        resolve(xhr.responseText) 
      }else{
        // 请求失败调用reject()
        reject(new Error(xhr.responseText))
      }
    }
    //发送请求
    xhr.send()
  })
}  
// 2 fetch请求
fetch(url).then( response => {
    return response.json()
}).then(data=>{
    // 请求成功,处理响应数据
    console.log("成功获取数据:", data);
}).catch(error=>{
    // 请求失败,处理响应数据
    console.error("获取数据失败:", data);
})

axios

  1. 是什么?前端最流行的ajax请求库,它的特点是:①基于promise封装的ajax请求库;②支持请求\响应拦截器;③支持取消请求;④浏览器和node端都能使用,浏览器端发起XMLHttpRequests请求,node 端发起 http 请求;
  2. 基本使用:①基本语法 axios({config});②快捷方法 axios.get(url, { params, ...config })
// 1 基本语法
axios({
    method:'get', url:'/api/user', params:{id: 1}, timeout:5000
}).then(response=>{
    console.log('请求成功:', response.data);
}).catch(error=>{
    console.error('请求失败:', error);
})
// 2 快捷方法
// i. get获取数据,请求指定的信息,返回实体对象
// ii post:向指定资源提交数据(例如表单提交或文件上传)
// ⅲ. put:更新数据,从客户端向服务器传送的数据取代指定的文档的内容
// ⅳ. patch:更新数据,是对put方法的补充,用来对已知资源进行局部更新
// ⅴ. delete:请求服务器删除指定的数据
// ⅵ. head:获取报文首部
axios.get(url, { params, ...config })//get参数通过params配置(自动拼接到URL的查询字符串)
axios.post(url, data, { ...config }) //post参数通过data传参 有请求体
axios.put(url, data, { ...config })
axios.delete(url, { params, ...config })

ajax、axios、fetch 的区别

  1. AJAX 即AsynchronousJavascriptAndXML(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。它可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

缺点:①基于原生 XHR 开发,XHR 本身的架构不清晰;②配置和调用方式非常混乱,而且基于事件的异步模型不友好。

  1. Fetch是ES6 基于标准 Promise 实现的,支持 async/await,代码结构比起 ajax 简单多。 脱离了XHR,不是 ajax 的进一步封装,没有使用 XMLHttpRequest 对象

缺点:①fetch 默认不会带 cookie,需要添加配置项: fetch(url, {credentials: 'include'});②fetch 不支持 abort,不支持超时控制,使用setTimeoutPromise.reject 的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费;③fetch 没有办法原生监测请求的进度,而 XHR 可以

  1. Axios 是一种基于 Promise 封装的 HTTP 客户端库,其核心是对浏览器端 XMLHttpRequest(XHR)和 Node.js 端 http 模块的现代化封装

特点:①基于promise封装的ajax请求库;②支持请求\响应拦截器;③支持取消请求;④浏览器和node端都能使用

链接

尚硅谷Promise教程(promise前端进阶)