自以为理解了宏任务与微任务,结果...为什么同步代码中的alert阻止了网络请求,宏任务中的却不行?

今天在知乎看到一篇文章https://zhuanlan.zhihu.com/p/...,讲的是宏任务与微任务
我以为我明白了
IO、settimeout都属于宏任务,事件循环的执行过程为script宏任务-》同步代码-》微任务-》渲染-》宏任务
直到我启node服务,输入了以下代码,才发现并没有理解
按照之前的理解,settimeout的time设置为0,那么它应该在任务队列的第一位。在清空执行栈中的同步代码后,应该先执行settimeout的function,再执行执行网络请求
可node服务接收到了网络请求,settimeout中的alert并没有阻止网络请求,为什么?网络请求不是IO吗?不是宏任务吗?难道网络请求比setTimeout(()=>{},0)更快进入任务队列?

setTimeout(() => {
    console.log('宏任务执行1');
    alert('暂停');
}, 0)

//自己封装的axios请求方法
App._post_form('adminUser/login', {}, (res) => {
}, (res) => {
    console.log('IO结束then微任务执行2');
})



//alert('暂停');

有朋友回答是因为网络请求发起是同步的,或者网络请求已经在其它线程发起,那么为什么主线程中的alert却可以阻塞网络请求呢?

image.png

可以看到此时并没有发起网络请求

image.png

封装的方法,较长

/**
 * post提交
 */
_post_form(url, data, success, fail, complete) {

    let _this = this;
    data.token = _this.getCookie('token');
    data.time = new Date().getTime();

    console.log('准备_post_form请求:' + url)

    /*因为 axios 发送数据时不是以 formData 的形式发送的,而 大多数后端 接收的是以 formData 形式的数据。所以只好把数据在请求之前转换一下。*/

    var params = new URLSearchParams();

    Object.keys(data).forEach((key) => {
        params.append(key, data[key]);
    });


    axios({
        method: 'post',
        url: _this.api_root + url,
        data: params,
    }).then(function (res) {

        console.log('_post_form--success(res)', res);
        //状态码不对
        if (res.status !== 200 || typeof res.data !== 'object') {
            layer.msg('网络请求出错');
            return false;
        }
        //登录态失效, 重新登录
        if (res.data.code === -1) {

            layer.alert(res.data.msg, function (index) {
                layer.close(index);
                window.location.href = "/login";
            });

            return false;
            //服务器返回错误
        } else if (res.data.code === 0) {


            // layer.alert(res.data.msg, function (index) {
            //     layer.close(index);
            fail && fail(res);
            // });


            return false;
        }
        //正常返回
        success && success(res.data);

        //通用方法
        complete && complete(res);
    }).catch(function (err) {
        console.log('_post_form--err(res)', err);

        //通用方法
        complete && complete(res);
    });
},
阅读 2.5k
2 个回答

发起网络请求的代码是同步的,返回结果的过程是异步的。

当前端发起fetch请求时,setTimeout还等在这个同步代码执行。当请求发起后,这个网络传输过程就已经不归前端管了,也就是已经处于pending状态。这个过程中即使alert阻断了js代码执行,数据已经在网络传输中了,也会正常返回服务端的结果。之所以F12还是显示pending状态,是因为alert阻断了返回结果的后续代码,并且F12没有及时更新。如果你在F12的NetWork里点击一下这个请求,更新一下它的页面状态,它的状态码已经变为200,说明这个请求已经成功完成与后端的交互。但是由于alert阻断,后续的代码无法执行而已。
image.png
image.png

目前测试出来两个结果:都是同步的情况下,axios会被后续的alert阻断,fetch和直接原生写 xhr 4个步骤都不会被阻断。那么可以推测一原因是axios封装的原因导致的,楼主研究下源码吧.

大致看了下axios的源码,之所以axios会被阻断,是因为调用axios后,返回的是一个promise.then,也就是说axios本身就已经变成异步的了,并且它是在then方法里发起的请求...
image.png

网络请求本身不在 js 的线程执行。它的回调在消息循环中执行。

网络请求是异步的,有自己的独立的线程。网络请求结束后,会把回调放进任务队列。

网络请求是 _post_form 发起的。只要它执行到了,就会发起请求。同步 alert ,alert 的时候 _post_form 还没有执行。settimeout alert ,执行 alert 的时候 _post_form 已经执行过了。

推荐问题
宣传栏