【异步1】

总结的内容:

  1. JS异步与单线程的关系(什么是单线程)
  2. event-loop事件轮询(JS异步由event-loop实现,异步是怎么执行的)
  3. jQuery中异步的解决方案(jQuery中的Deferred)

★JS异步与单线程的关系

JS是单线程的。

单线程:只有一个线程、同一时间只能做一件事。两端JS代码不能同时执行
原因:为了避免DOM渲染的冲突。

  • 浏览器需要渲染DOM
  • JS可以修改DOM
  • 因此,JS的执行和浏览器渲染DOM的执行共用一个线程。JS执行的时候,浏览器渲染DOM会暂停。(都修改DOM就冲突了)
  • webworker支持多线程,但是不能访问DOM

    单线程的解决方案:异步[async/await、promise解决方案](虽然也有问题)
    在这里插入图片描述
    异步解决:
    在这里插入图片描述
    在这里插入图片描述
    异步解决单线程的问题:
  • 没按照书写顺序执行,可读性差
  • callback中不容易模块化

★event-loop事件轮询
异步的实现方式event-loop

  • 事件轮询,JS实现异步的具体方案
  • 同步代码直接执行
  • 异步函数先放入异步队列中
  • 待同步函数执行完毕,轮询执行 异步队列 中的函数

实例分析一:
在这里插入图片描述
在这里插入图片描述
等主进程中的函数执行完,将异步队列中的函数放入主进程中执行
实例分析二:
在这里插入图片描述
在这里插入图片描述
事件轮询执行步骤:

  1. 主进程执行到第一个setTimeout,看是个异步,等100ms之后放入异步队列中
  2. 下来执行到第二个setTimeout,是个异步,直接放入异步队列中
  3. 主进程直接执行console.log(3);
  4. 同步代码执行完成后看异步队列中有没有函数
  5. 这时异步队列中只有第二个setTimeout函数
  6. 将第二个setTimeout中的函数拿到主进程中执行
  7. 立即到异步队列中看看还有没有要执行的函数
  8. JS引擎会轮询着来看异步队列中有没有
  9. 100ms之后,第一个setTimeout中的函数放入异步队列
  10. JS引擎会立刻将这个函数放入主进程中执行

事件轮询event-loop像一个哨兵一样,监视异步队列,只要有函数进入异步队列,立刻将函数拿到主进程中执行,立即又回去监视着

实例分析三
在这里插入图片描述
在这里插入图片描述
ajax加载完成时放入异步队列
所以实例分析三的结果可能是dcba 也可能是dcab

event-loop总结:

  1. 同步代码,直接执行
  2. 异步函数先放入异步队列中【异步定时0ms直接放入异步队列,异步定时100ms是100ms之后放入异步队列,ajax请求成功后将callback函数放入异步队列】
  3. 待同步函数执行完毕,轮询执行异步队列的函数

★ jQuery中异步的解决方案
jQuery1.5的变化
jQuery1.5之前ajax请求写法:

var ajax=$.ajax({
    url:"data.json",
    success:function(){
        console.log("success1");
        console.log("success2");
        console.log("success3");
    },
    error:function(){
        console.log(error);
    }
})
console.log(ajax);    //返回一个XHR对象

对修改开放,对扩展封闭,不满足开放封闭原则

jQuery1.5之后ajax请求写法:

var ajax=$.ajax("data.json");
ajax.done(function(){
    console.log("success1");
}).fail(function(){
    console.log("error");
}).done(function(){
    console.log("success2");
})
console.log(ajax);    //返回一个deferred对象

到最后:很像promise的写法

var ajax=$.ajax("data.json");
ajax.then(function(){
    //成功回调
},function(){
    //失败回调
}).then(function(){
    //成功回调
},function(){
    //失败回调
})

与promise相似,所以promise是先从jquery开始的。.fail .done .then这种形式是通过jQuery.deferred实现的

对修改封闭,对扩展开放,满足开放封闭原则

jQuery1.5的变化

  • 无法改变JS单线程的本质
  • 只能从写法上杜绝callback这种形式
  • 它是一种语法糖形式,但是解耦了代码
  • 很好的体现了:开放封闭原则(多人开发有质的提高,有错误时好查,极大地减少了有错误时排查错误的能力)

jQuery Deferred的使用:

var wait=function(){
    var task=function(){
        console.log("执行完成");
    }
    setTimeout(task,2000);
}
wait();
//新增需求,要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤。
//可以直接在console.log("执行完成")后面写,但不符合开放封闭原则,所以不能这样写,需要使用jQuery Deferred

使用jQuery Deferred:

function waitHandle() {
    var dtd = $.Deferred();   //创建一个deferred对象
    var wait = function (dtd) {   //要求传入一个deferred对象
        var task = function (){
            console.log("执行完成");
            dtd.resolve();   //表示异步任务已经完成
            //dtd.reject();   //表示异步任务失败或是出错
        }
        setTimeout(task,2000);
        return dtd           //要求返回deferred对象
    }
    //注意,这里一定要有返回值
    return wait(dtd);
}

var w=waitHandle();     //deferred对象
w.then(function(){
    console.log("success1");
},function(){
    console.log("error1");
}).then(function(){
    console.log("success2");
},function(){
    console.log("error2");
})

多个.then,对扩展开放,对修改封闭,满足开放封闭原则,若都写在console.log(“执行完成”)后面,则不满足开放封闭原则。

Deferred总结:

dtd的API可分为两类:

  1. dtd.resolve dtd.reject (系统主动执行)
  2. dtd.then(监听) dtd.done dtd.fail (被动调用)
    dtd.then包含两个参数,若成功,执行第一个参数,即dtd.resolve。若失败,执行第二个参数,即dtd.reject。
    注意:这两类API不能混合使用

jQuery1.5之后,wait函数返回的是dtd.promise()。

function waitHandle() {
    var dtd = $.Deferred();   //创建一个deferred对象
    var wait = function (dtd) {   //要求传入一个deferred对象
        var task = function (){
            console.log("执行完成");
            dtd.resolve();   //表示异步任务已经完成
            //dtd.reject();   //表示异步任务失败或是出错
        }
        setTimeout(task,2000);
        return dtd.promise()           //要求返回deferred对象
    };
    //注意,这里一定要有返回值
    return wait(dtd);
}

var w=waitHandle();     //经过上面的改动,w接收的是一个promise对象
w.then(function(){
    console.log("success1");
},function(){
    console.log("error1");
}).then(function(){
    console.log("success2");
},function(){
    console.log("error2");
});

w.reject();    //执行这句话直接会报错   因为返回promise对象,则w只有.then  .done  .fail这种被动监听的方法,把dtd的reject  resolve给过滤掉了,外面不能再调用,只有我封装的时候才可以调用。

(promise和deferred的对比)deferred可以主动调用reject和resolve方法,所以有可能被别人篡改代码,而promise只能调用.then .done .fail这种被动监听的方法,别人不能修改,比较安全,也满足开放封闭原则。

(promise和deferred的区别)Deferred实例既可以执行.resolve .reject这种主动执行的函数,又可以执行.then .fail .down这种被动监听结果的函数,但这两类放在一起会发生冲突,又封装出了Promise对象,Promise只能去被动监听.done .then .fail这种结果,不能主动干预失败成功的操作,完美解决了问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值