javascript考点高级 —— 异步

一、什么是单线程,和异步的关系

  • 单线程,只有一个线程,只能做一件事
  • 原因,避免DOM渲染的冲突
  • 解决方案异步

1、看如下单线程例子:

//循环运行期间,JS执行和DOM渲染暂时卡顿
var i, sum = 0;
for(i = 0; i < 1000000000; i++){
    sum += i
}
console.log(sum)

//alert不处理,JS执行和DOM渲染暂时卡顿
console.log(1)
alert('hello')
console.log(2)

2、为什么会有单线程,原因是避免DOM渲染冲突

浏览器需要渲染DOM,JS可以修改DOM结构,JS执行的时候,浏览器DOM渲染会暂停,两段JS也不能同时执行(都修改DOM冲突)。JS执行的时候和浏览器渲染DOM在一个线程中,否则会出现DOM渲染冲突。HTML5中的webworker支持多线程,但是不能访问DOM。

3、解决单线程的办法——异步

(1)先看下面异步的例子:

console.log(100)
setTimeout(function() {
    console.log(200)
})
console.log(300)
console.log(400)
console.log(100)
$ajax({
    url:'xxxxxx',
    success: function(result) {
        console.log(result)
    }
})
console.log(300)
console.log(400)

(2)异步的一些问题:

  • 没按照书写的方式执行,可读性差
  • callback中不容易模块化

二、什么是event-loop

event-loop就是事件轮询,JS实现异步的具体解决方案(原理)。具体执行过程:(1)同步代码,直接执行。(2)异步函数先放在异步队列中。(3)待同步函数执行完毕,轮询执行异步队列的函数。

1、实例分析

 在上述的图里面,第一个setTimeout会立即放入异步队列,第二个setTimeout会100ms之后被放入异步队列中,然后主进程执行结束后,就去执行异步队列,当主进程执行完,有可能第二个setTimeout还没有放入异步队列中,这时JS搜索引擎就会轮询异步队列,如果有就将其执行。

3、轮询是什么意思

  • 浏览器会监视异步队列,只要异步队列里面有东西,就立刻拿去执行,然后又继续监视异步队列。

三、jQuery的Deferred

1、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('success1')
})
console.log(ajax)     //返回了一个deferred



//第二种写法
var ajax = $.ajax('data.json')
ajax.then(function(){
    console.log('success1')
}, function(){
    console.log('error1')
})
.then(function(){
    console.log('success2')
}, function(){
    console.log('error2')
})

jQuery1.5的变化,但是无法改变JS异步和单线程的本质,只能从写法上杜绝callback这种形式,它是一种语法糖式,但是解耦了代码,很好的体现了开放封闭原则。

2、jQuery  Deferred

jQuery1.5的变化在jQuery中添加了Deferred,之前是没有的。然后jQuery Deferred的语法就没有变过。

(1)先看如下的例子:

var wait = function() {
    var task = function(){
        console.log('执行完成')
    }
    setTimeout(task, 2000)
}
wait()

现在假设我们执行之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤,我们该怎么做?

(2)在来看如下的例子:

function waitHandle() {
    var dtd = $.Deferred() //创建一个deferred对象
    var wait = function(dtd) {
        var task = function() {  //要求传入一个eferred对象
            console.log('执行完成')
            dtd.resolve()    //表示异步任务已经完成
            //dtd.reject()   //表示异步任务失败或出错,如果执行reject,后面不能使用链式操作
        }
        setTimeout(task, 2000)
        return dtd     //要求返回一个deferred对象
    }
    return wait(dtd)    //这里一定要有返回值
}
var w = waitHandle()
//w.reject()   //这样使用很不规范,下面输出结果是error 1    error  2
w.then(function() {
    console.log('ok 1')
}, function(){
    console.log('error 1')
}).then(function() {
    console.log('ok 1')
}, function() {
    console.log('error 2')
})

//还有w.done   w.fail

dtd的API可分为两种,用意不同,第一类(主动执行):dtd.resolve  dtd.reject。第二类(被动监听):dtd.then  dtd.done  dtd.fail。这两个类必须分开,否则后果很严重。为了解决外部使用主动执行的第一类API,我们引出了promise。

function waitHandle() {
    var dtd = $.Deferred() 
    var wait = function(dtd) {
        var task = function() {  
            console.log('执行完成')
            dtd.resolve()    
            //dtd.reject()   
        }
        setTimeout(task, 2000)
        return dtd.promise     //这里就是解决办法
    }
    return wait(dtd)    //这里一定要有返回值
}
var w = waitHandle()    //经过上面的改动,w接受的就是一个promise对象
$.when(w)
.then(function(){
    console.lof('ok 1')
 })
.then(function(){
    cinsole.log('ok 2')
})

//这里执行w.reject()这句话会直接报错

3、关于defrred问题,怎么回答,可以从以下几个方面回答

  • 可以对jQuery1.5之前和之后的ajax进行对比
  • 说明如何简单的封装,使用Deferred
  • 说明promise和Defrred的区别

四、Promise的基本原理

1、Promise的基本语法回顾

2、异常捕获

function loadImg(src) {
    const promise = new Promise(function (resolve, reject) {
        var img = document.createElement('img')
        img.onload = function() {
            resolve(img)
        }
        img.onerror = function() {
            reject('图片加载失败')    //为了让catch一起捕获逻辑之外的语法异常,我们传了一个参数  ‘图片加载失败’
        }
        img.src = src
    })
    return promise
}
var src = 'http://www.imoooc.com/static/img/index/logo_new.png'
var result = loadImg(src)

//then只接受一个参数,请求成功的函数,最后统一用catch捕获异常
result.then(function(img){
    console.log(img.width)
    return img
}).then(function(img){
    console.log(img.height)
}).catch(function(ex){
    console.log(ex)
})

3、多个串联

var src1 = '.........'
var result1 = loadImg(src1)
var src2 = '..........'
var result2 = loadImg(src2)

//链式操作
result1.then(function(img1){
    console.log('第一个图片加载完成')
    return result2
}).then(function(img2){
    console.log('第二张图片加载完成')
}).catch(function(ex){
    console.log(ex)
})

4、promise-all-race

Promise.all接受一个promise对象数组,Promise.race接受一个包含多个promise对象的数组。

//这里的result1和result2就是上面代码中的result1和result2
//待全部完成之后,统一执行success
Promise.all([result1, result2]).then(datas => {
    //接收到的datas是一个数组,依次包含多个promise返回的内容
    console.log(datas[0])
    console.log(datas[1])
})

//只要完成一个,就执行success
Promise.race([result1, result2]).then(data =>{
    //data即最先执行完成的promise的返回值
    console.log(data)
})

5、Promise标准

(1)标准

任何技术推广都需要一套标准来支撑。任何不符合标准的东西,终将会被用户抛弃。不要挑战标准,不要自造标准。

(2)状态变化

  • 三种状态:pending   fulfilled  rejected
  • 初始状态就是pending
  • pending可以变成fulfilled,pending可以变为rejected
  • 状态不可逆

(3)then

  • Promise实例必须实现then发方法
  • then()必须接受两个函数作为参数
  • then()返回的必须是一个Promise实例(如果Promise的then()没有铭文的返回实例,那么实例就是then()方法前面的本身的实例,如果返回了,后面的而执行就是返回的实例)

五、async/await(ES7提案)

then只是将callback拆分了(看前面的例子),但是还是异步的写法。async/await是最直接的同步写法。

1、async/await的语法:

//同步的写法
const load = async function(){
    const result1 = await loadImg(src1)       //前面代码中的src1
    console.log(result1)
    const result2 = await loadImg(src2)       //前面代码中的src2
    console.log(result2)
}
load()

2、用法

  • 使用await,函数必须用async标识
  • await后面跟的是一个Promise实例
  • 需要用babel-polyfill

3、问题解答

  • 使用了Promise,但没有和Prromise冲突
  • 完全是同步写法,没有回调函数(它和Promise做了完美的结合)
  • 但是:改变不了JS单线程、异步的本质

六、总结

  • 什么是单线程,和异步有什么关系

解答:单线程就是同时只做一件事情,不能同时执行两段JS代码。原因是避免DOM渲染冲突。然后就出现了异步,异步是一种“无奈”的解决方案,虽然有很多问题。

  • 什么是event-loop

解答:就是事件轮询,JS异步的解决方案。什么是异步队列,何时被放入异步队列(没有时间参数,立即放入。有时间参数,等待时间过后,加入异步队列。有请求时,请求成功放入异步队列)。轮询的过程。

  • 是否用过jQuery的Deferred

解答:对比jQuery1.5前后的ajax。说明如何简单的封装、使用Deferred。说明promise和Deferred的区别。

  • Promise的基本使用和原理

解答:基本语法。如何捕获异常。多个串联-链式执行的好处。Promise.all和Promise.race。Promise的标准-状态变化、then函数。

  • 介绍一下async/await(和Promise的区别)

解答:使用了Promise,但是没有和Primise冲突。完全同步的写法,没有回调函数。

  • 总结一下当前JS解决异步的方案

解答:(1)jQuery  Defrred。(2)Promise。(3)Async/Await。(4)Genterator(并不是异步的直接替代方式,解决异步需要很复杂的封装)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值