先说说异步是什么,众所周知js是单线程的,从而导致一些类似等待的操作会使js停止工作,异步就是为解决此类问题而生。
异步的过程是把需要等待执行的动作,比如延时,ajax等放入异步队列,在主线程任务完成后,通过event-loop检查异步队列中是否有待执行任务,有则放入主线程中执行。这种做法的目的是为了保证dom操作的唯一性,避免多处同时操作dom。
但是异步本身是存在一些问题,主要问题是异步的书写顺序跟执行顺序不一致,阅读性差,容易造成回调地狱。所以我们谈的异步解决方案都是为了这一问题,所有的解决方案都无法违背js单线程的基础,只能是通过一些语法糖或书写方式来让书写跟执行顺序一致。
最初的异步都是通过callback,后来jquery提出了deferred 方式和promise 概念,最后在es6中把promise统一规范,es7中在promise基础上延伸出终极解决方案 async、await。
下面通过伪代码演示异步的解决方式是怎么一步步把书写顺序跟执行顺序保持一致的
// jquery 最初的ajax请求
$.ajax({
url: 'xxx',
success: function() {
// ajax 执行成功后,所有的异步操作都是在此处理
// 缺点: 所有的处理都在这个函数里,不利于维护,不利于扩展,不利于阅读,如果还需要发送ajax
请求,就造成了回调地狱
},
error: function() {
}
})
// jquery Deferred 发送ajax
function sendAjax() {
var dfd = $.Deferred();
$.ajax({
url: 'xxx',
success: function(res) {
dfd.resolve(res)
},
error: function(err) {
dfd.resolve(err)
}
})
return dfd.promise();
}
// 请求结果在此处理,具体用法这里不详细写了
// 对比callback直接处理,这里已经把书写的方式优化了,扩展性维护性得到提升
// 缺点:书写顺序跟执行顺序得到了控制,但是没完全解决。并且通过 .then的操作还是会存在回调地狱
sendAjax().then()
// promise 封装请求
function sendAjax() {
return new Promise((resolve, reject) => {
$.ajax({
url:'https://ss2.baidu.com',
success: (res) => {
resolve(res)
},
error: (error) => {
reject(error)
}
})
})
}
// async await的用法
async function getData() {
const data = await sendAjax()
console.log(data)
// 可以看到,这里是可以直接处理ajax的请求结果的,await后面必须跟着 Promise对象,它其实
// 就是个语法糖,替换掉 .then()的方式。发展到这个阶段,异步的书写顺序跟执行顺序已经一致了
}
getData()