学会使用JavaScript的异步及优化

学会使用JavaScript的异步及优化

0.异步的认识对比并行机制

0.1异步的定义

​ 指程序的一部分现在运行,而另一部分则在将来运行,现在与将来之间有时间空隙,在此间隙中程序没有活跃执行。

​ 异步编程指的就是程序现在运行的部分和将来运行的部分之间的关系,对比for循环,虽然执行也需要几微秒的时间,却可以称之为同步的而非异步执行!!

0.2异步的思考

  • 如何实现异步,有多少方法?
//只需要将一段代码包装为一个函数(包括回调函数),并指定其在响应某个事件(定时器,鼠标点击,Ajax响应等)
//执行,意味着你已经创建了一个将来执行的代码块,也就在此程序中引入了异步机制!!
setTimeout(function later(){
    console.log("我被异步执行了!")
},1000)



function later(){
    console.log("将来才会被执行!")
}
setTimeout(later,1000)
function now(){
    return 21
}
var answer=now()
console.log("现在就执行:",answer)

由此可以看出:异步机制的必要条件有,(1)将来执行的函数,(2)触发将来执行函数的事件

  • 怎样管理异步?
//如果不能有效控制异步编程机制,有可能在代码编写时出现出乎意料的结果
//比如:对于浏览器的异步控制台I/O,就是异步输出
var a={
    index:1
}
console.log(a)
a.index++
//一般情况下,会先输出{index:1},在增1,但是如果在控制台异步输出延迟下,就会出现输出{index:2}

//所以必须对异步机制进行有效的管理,防止出现不可控的结果!!

注:

​ JavaScript引擎不是独立运行的,必须运行在宿主环境中,如浏览器,node.js,JavaScript引擎本身在需要

的时候,在给定的任意时刻解释执行程序的单个代码块,尽管运行的环境不尽相同,但是都有一个共同的点,就是

都提供一种机制来处理程序中多个块的执行,每次执行块是则调用JavaScript引擎,被称为事件循环

记住一点:JavaScript引擎只负责在执行代码块时解释执行,但其本身没有时间概念,事件(代码的执行)调度都是由宿主环境进行的!!

**举例:**JavaScript程序发出一个Ajax请求,设置好响应后的执行函数(通常为回调函数),之后JavaScript引擎就会通

知宿主环境(即浏览器或者node.js),浏览器就会设置监听网络的响应,一旦拿到响应的数据,就会将回调函数插入

到事件循环机制中,并调用JavaScript引擎执行!!

事件循环机制:

//使用伪代码进行模拟事件循环机制
var eventLoop=[]
var curEvent
while(ture){
    if(eventLoop.length>0){
        curEvent=eventLoop.shift()
    }
    try{
        event()//这些事件就是你的回调函数!!
    }catch(err){
        reportError(err)
    }
}

//setTimeout并没有将你的回调函数加入事件循环队列中,它只是设置一个定时器的作用,当定时到了之后,
//宿主环境会将回调函数加入到事件循环队列中,如果在它之前还有其他事件在等待,就只能等待前面项目执行完
//也就是说setTimeout定时器不会严格精度执行回调函数,这与当前事件队列状态而定!!

//在ES6中引入Promise,从而使JavaScript引擎开始接管事件循环的控制,而不是宿主环境,也就是说使用
//Promise能够精确控制事件循环的调度执行!!

0.3 异步对比并行机制和并发机制

/*
	1.异步是关于现在和未来的时间间隙,而并行指能够同时发生的事情
	2.并行计算的机制通常使用进程和线程,二者能够同时运行,每个线程都有各自的调用栈,但是共享同一个
		进程的内存数据
而与之相对的异步执行的事件循环机制,是将当前的工作分成一个个独立的任务顺序执行,能够访问共享内存,
	但是不能够同时访问,,但是如果将事件循环分配给多个线程并行执行,则可以同时共享内存!!!
	
	3.如果是多个线程执行事件循环,有可能对那些有顺序依赖的事件出现不同的执行结果!!所以必须通过某
	中机制防止多个线程的交错和中断执行,保证执行的确定、准确性!!!
	
	由此看出:调用多个线程虽然能够处理更多的任务,但是也会出现不确定结果的不良后果!!!
	
	4.JavaScript具有单线程运行的特点,所以代码具有原子性,没有多线程执行的诟病!!
	
		但是对于多个异步执行块,由于都不确定它的执行时间,也就无法确定谁先执行,但是这种不确定性
		只是建立在事件函数级别上,而不是多线程执行的顺序级别,
		换而言之,JavaScript尽管为单线程机制,但是由于事件循环的不确定性,也会出现代码块执行的
		竞争状态,看谁会被先执行!!!于是引入了生成器,解决这一个缺点!!
*/

对比并行和并发机制:并发是在进程任务级的同时执行,而并行为线程级的运算处理级的同时执行!!

/*
	假想:不断下拉一个网站列表,会逐渐加载更多的内容,其中至少需要两个“进程”同时运行
		第一个进程不断触发onscroll事件的请求函数
		第二个进程则接受Ajax的响应数据,并将数据加载到页面中,
		随着下拉速度的加快,就会出现多个请求的并发进行,同时出现多个并发的Ajax响应接收运行!!
		
		也就是说,并发是在进程任务级的同时执行,而并行为线程级的运算处理级的同时执行!!
		
		不同进程之间也能够进行交互,如果不同进程不相关则不会发生交互,相关可能会发生交互!!
		一旦发生交互,就需要对他们之间的交互进行协调,避免竞争状态的发生,修改回调函数代码!!
		但是不同于线程共享内存数据!!
	
*/
var res=[]
function response(data){
    res.push(data)
}
ajax("url1",response)
ajax("url2",response)//res的响应不确定,出现竞争态


var res=[]
function response(data){
    if(data.url=="url1")
        res[0]=data
    else if(data.url=="url2")
        res[1]=data
}

ajax("url1",response)
ajax("url2",response)//通过修改回调函数,从而协调了并发执行出现的竞争态!

//通过协作的方法:如果当前处理的事件需要消耗大量的时间,不可能一直等待,后面还有一大堆的事件等待执行
//这时必须通过协作的方法,另外开辟一个线程,如果后面的事件不依赖后面的事件,则直接处理后面的事件
//,如果依赖,则线程协同一起处理当前的大事件,从而避免了一直等待!!


0.4 对比事件循环机制和任务循环机制

  • **事件循环机制:**必须等待前面的事件执行完才能够执行

  • **任务循环机制:**表示如果执行过此任务,还需要执行,则可以插队执行,而不需要等待前面任务的执行

记住Promise是基于任务循环机制的!!!!!!!

0.4 记住在JavaScript中,语句的执行顺序与js引擎的执行顺序不一定一致,所以对代码的调试相比其他语言困难

1.异步的基础------异步模式的主力军回调函数

/*
	1.回调函数的缺点:对于适应顺序执行的大脑而言,异步执行的方式会使js代码难以跟踪,调试
	2.更为主要的是对于多个回调函数,由于需要对函数输入进行安全类型检查,使得代码的维护性差
		此外,由于回调函数的异步依赖性,想要更新修改某个函数,就必须全部整体的进行调整,
		可谓真正的回调地狱!!!
	3.为了解决信任问题,可以使用API分离回调函数,一个用于执行成功时候的回调,一个用于执行失败时候的
		回调
	
*/
    //设置成对的回调
    function success(data){
        ...
    }
    function failure(data){
        ...
    }
    ajax("url",success,failure)
    
    
	//设置超时取消
    function timeoutify(fn,delay){
        var inde=setTimeout(function(){
            inde=null
            fn(new Error("timeout"))
        },delay)
        return function(){
            if(inde){//没有超时
                clearTimeout(inde)
                fn.apply(this.arguments)
            }
        }
    }
    ajax("url",timeoutify(foo,1000))

注:总之回调函数实现异步主要有两大缺陷,缺乏顺序性和可信任性

2.异步的优化-------更高级的异步模式Promise精确控制事件循环的调度执行!!

3.生成器------解决js事件循环的竞争状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值