三、《揭秘一线互联网企业 前端JavaScript高级面试》视频教程总结系列三:JS异步 相关

 


 

系列目录:https://www.cnblogs.com/lmyxywy/p/10931603.html

 


 

问题一:单线程是什么?和异步有什么联系?

 

单线程是同一时间只做一件事,两段js不能同时执行。

这是因为js可以操作Dom,为了避免两段js同时修改一个Dom元素从而发生冲突,所以js的作者采用了单线程机制。

另外,因为浏览器的UI渲染需要渲染Dom元素,所以为了避免和js起冲突,UI渲染和js也是在同一个线程里的;

其中js修改Dom的时候,UI渲染需要暂停。

两者单线程的实质都是为了避免Dom渲染冲突。

 

根据单线程的原理,一件事没做完之前程序就不往下走,这样势必就会导致等待,等待时间长了次数多了就会造成阻塞。

异步就是解决单线程阻塞问题的一种“无奈”的解决方案。

异步的原理:通俗来讲,就是遇到需要等待的事件,先略过,继续往下走同步的事件,等到到达处理异步事件的时间时,再回头执行异步事件。

 

 异步导致的问题:

1、不按照书写顺序执行,可读性非常差,不利于理解和调试;

2、callback(回调函数)嵌套层级非常多,耦合度相当高,不容易模块化。

 


 

问题二:什么是event-loop?什么是异步队列,何时被放入异步队列?

 

event-loop是事件轮询,JS实现异步的具体解决方案。

 

event-loop执行原理:

1、所有同步任务都放在主线程中执行,形成一个执行栈;

2、遇到异步任务,暂不执行,将任务插入到异步队列中,它是主线程外专门存放异步任务的队列

        放入异步队列的时机分三种情况:

        ①没有规定延迟时间,立刻放入异步队列中;

        ②有延迟时间,到了延迟时间再放入异步队列中;

        ③类似Ajax,需要等待返回的数据,何时接收到数据何时放入异步队列。

3、等到主进程中的所有同步任务执行完毕时,监听异步队列,轮询执行异步任务。

(轮询是指:只要主线程空了,异步队列中的任务就会进入执行栈,等待执行栈执行完毕,系统再去异步队列中监听读取任务,让异步任务进入执行栈,循环往复)

 


 

问题三:是否使用过Jquery的Deferred?

 

Jquery Deferred是Promise的前身,改变了异步任务必须使用回调函数来书写的方式。

 

1、先介绍下deferred的使用实例——Jquery1.5前后Ajax写法的变化

 

Jquery1.5之前,没采用deferred,异步只能采用callback(回调函数)的形式,代码都堆在一块,无法模块化,不便于扩展(对修改开放、对扩展封闭)。

var ajax = $.ajax({
    url:'data.json',
    success:function () {
        console.log('success 1');
        console.log('success 2');
        console.log('success 3');
    },
    error:function () {
        console.log('error');
    }
});
console.log(ajax); // 返回一个XHR对象

 

Jquery1.5之后,采用了deferred,deferred对象调用的第一种写法,异步可以采用链式调用,done、fail两个函数成对出现,将异步函数按照同步的逻辑书写与执行,代码实现了模块化。

var ajax = $.ajax('data.json');
ajax.done(function () {
    console.log('success 1');
})
.fail(function () {
    console.log('error 1');
})
.done(function () {
    console.log('success 2');
})
.fail(function () {
    console.log('error 2');
})
.done(function () {
    console.log('success 3');
})
.fail(function () {
    console.log('error 3');
})
console.log(ajax); // 返回一个deferred对象

 

Jquery1.5后采用deferred,调用的第二种写法,也是链式调用,函数和容错函数都包含在了then里面,已经相当接近ES6中的Promise了。

var ajax = $.ajax('data.json');
ajax.then(function() {
        console.log('success 1');
    }, function() {
        console.log('error 1');
    })
    .then(function() {
        console.log('success 2');
    }, function() {
        console.log('error 2');
    })
    .then(function() {
        console.log('success 3');
    }, function() {
        console.log('error 3');
    })

 Jquery1.5之后Ajax的写法,体现了五大设计原则中的开放封闭原则(对修改封闭、对扩展开放),更加方便开发人员的修改、扩展与协同开发。

它以一种语法糖的形式解耦了代码,是从写法上杜绝了callback这种形式,并不能改变js单线程和异步的本质。

 

2、介绍Jquery Deferred 的具体用法,封装一个deferred(非常类似于封装Promise)

 

原始代码及需求

// setTimeout模拟异步
var wait = function() {
    var task = function() {
        console.log('打印一')
    }
    setTimeout(task, 2000);
}
wait()

// 需求为,在'打印一'后每个2秒分别打印'打印二','打印三'

 

 使用Jquery的deferred,将函数封装之后

function waitHandle() {
    var dtd = $.Deferred(); // 创建一个deferred对象
    
    return wait = function (dtd) { // 传入deferred对象,并作为promise对象返回
        var task = function () {
            console.log('打印一')
            dtd.resolve() // 表示异步任务已完成
        }
        setTimeout(task, 2000);
        return dtd.promise() // 要求返回promise对象,防止外部调用dtd.resolve()或dtd.reject()阻止进程
    }
}

 

调用封装好的deferred方法,这里用的是then,另一种写法还可以将一个then()替换成一对的done(),fail()

var w = waitHandle()
    w.then(function() {
        console.log('打印二')
    })
    .then(function() {
        console.log('打印三')
    })

以上便是deferred的用法。

 

总体回答汇总:

Jquery Deferred是Promise的前身,改变了异步任务必须使用回调函数来书写的方式。

使用deferred后,可以将异步函数按照同步的逻辑书写与执行,代码实现了简单的模块化。

Jquery1.5之后Ajax的写法使用了deferred,可以链式调用,体现了五大设计原则中的开放封闭原则(对修改封闭、对扩展开放),更加方便开发人员的修改、扩展与协同开发。

它以一种语法糖的形式解耦了代码,虽然从写法上杜绝了callback这种形式,但并没有改变js单线程和异步的本质。

 

deferred有两类API:

第一类是dtd.resolve()、dtd.reject(),这类是主动触发的方法;

第二类是dtd.then()或dtd.done()、dtd.fail(),这一类是被动接受的方法;

两类方法不可以在一起混用,否则会造成程序混乱。

所以为了避免这一问题,在封装deferred的时候,最终返回的应该是dtd.promise(),

这样就过滤掉了dtd.resolve()和dtd.reject(),使外部无法调用deferred对象的resolve()、reject()。

 


 

问题四:Promise的基本使用和原理。

 

1、基本语法

    ①封装:

        ——new 一个Promise对象,传入一个函数,函数有两个参数,分别是resolve()和reject()方法;

        ——在Promise对象内部书写具体逻辑,成功则resolve(), 失败则reject ();

        ——最后返回new出来的这个Promise对象。

    ②调用:使用.then()链式调用,then接收两个函数,一个是成功函数,一个是失败函数。

    (以下我就偷个懒不放代码,直接放截图辣)

    

 

2、异常捕获

    每个then都接收两个函数比较麻烦,使用异常捕获就方便许多,

    异常捕获规定then只接受一个参数,最后统一用catch捕获异常。

    catch可以捕获两种错误,一种是逻辑之外的错误(语法报错),一种是逻辑内的错误(reject抛出的错误)。

    

 

 

3、多个串联

    在前一个then中返回一个Promise对象,下一个then接收参数的就是上一个Promise对象resolve出来的结果。

    

 

下班啦,未完待续。。。

 

4、Promise.all() 、Promise.race()

5、Promise的标准

 


 

问题五:介绍一下async/await(和Promise的区别和联系)

 

posted @ 2019-08-06 16:39  李呀嘛李Yy  阅读(420)  评论(0编辑  收藏  举报

博主声明:QQ与微信皆是法定工作时间在线,其他时间无法联系,法定节假日是多么的重要,可不能被任何事情打扰。

Copyright ©2019 李呀嘛李Yy

QQ:781849676

微信:qjyjhl