异步操作和ajax原理以及回调地狱

异步操作和ajax原理以及回调地狱

异步操作

JS是单线程的

就是同一个时间只能处理一个任务。就类似生活中的去超市排队结账,正常情况下,一位收银员只能为一位顾客结账,其他顾客需要在后面排队等候。

为什么 JS 是单线程的?作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM 。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JavaScript同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

单线程就意味着,所有任务都需要排队,前一个任务结束,才能执行后一个任务。如果前一个任务耗时很长,那么后一个任务就不得不一直等待,于是乎,JS 设计者们把所有任分成两类,同步和异步。

同步:只有前一个任务执行完毕,才能执行后一个任务
异步:当同步任务执行到某个 WebAPI 时,就会触发异步操作,此时浏览器会单独开线程去处理这些异步任务。

 // 同步
 const a = 2
 const b = 3
 console.log(a + b)

 // 异步
 setTimeout(() => {
     console.log(a + b)
 }, 1000)

请思考下面的输出结果是什么?

console.log(1)
setTimeout(() => { // 异步任务,放入任务队列中
    console.log(2)
}, 0)
console.log(3)

// 1、3、2

下图说明了同步任务和异步任务的执行过程:
在这里插入图片描述

Ajax原理

Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

// 创建 XMLHttpRequest 对象
const url = 'http://jsonplaceholder.typicode.com/users'
let xmlhttp
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp = new XMLHttpRequest()
} else { // code for IE6, IE5
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
}

// 发送请求
xmlhttp.open("GET", url, true)
xmlhttp.send()

// 服务端响应
xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        //    console.log(xmlhttp.responseText)
        let obj = JSON.parse(xmlhttp.responseText)
        console.log(obj)
    }
}

Callback Hell

JavaScipt 中的许多操作都是异步的,我们把上面的Ajax封装成一个函数:

function ajax(url, callback) {
    let xmlhttp
    if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest()
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
    // 发送请求
    xmlhttp.open("GET", url, true)
    xmlhttp.send()
    // 服务端响应
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            //    console.log(xmlhttp.responseText)
            let obj = JSON.parse(xmlhttp.responseText)
            callback(obj)
        }
    }
}

我们在static文件夹下放入三个json文件:

a.json:

{
    "a": "我是A"
}

b.json:

{
    "b": "我是B"
}

c.json:

{
    "c": "我是C"
}

我们可以像这样使用:

/

/ 加载并执行脚本
ajax('/static/a.json')

函数是异步调用的,因为操作不是立即完成的,而是之后才会完成。

ajax('/static/a.json')
// 下面的代码不会等到ajax执行完才执行
// ...

这个过程大家并不陌生,可是如果在回调之后再回调呢?

ajax('static/a.json', res => {
    console.log(res)
    ajax('static/b.json', res => {
        console.log(res)
        ajax('static/c.json', res => {
            console.log(res)
        })
    })
})

这样确实解决了异步操作的执行顺序问题但是却也出现了新的问题
如果嵌套变多,代码层次就会变深,维护难度也随之增加。
这就被称为 “回调地狱” 或者“回调深渊”。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值