Javascript中的异步

2年前 (2022) 程序员胖胖胖虎阿
187 0 0

 

Javascript中的异步


Web项目聚集地

前沿技术交流,资源分享

Javascript中的异步 

















     

????????

前言

博客地址:www.illgo.cn


    在Javascript这样类型的语言中编程最重要但最常被人误解的部分之一,就是如何控制在一段时间内程序的行为次序.同时,JavaScript中的异步,也经常被人和并行搞混.今天,我们来谈一下JavaScript中的异步.
    自
JS开始以来,异步编程一直存在.然而,但是大多数JS开发人员从未真正仔细考虑过在程序中如何以及为何出现问题,也没有去探索各种其他处理方法。 比较好的方法一直是稀里糊涂的使用回调函数.到今天为止,许多人会坚持认为回调使用起来就已经绰绰有余了.

什么是异步?

    首先,一段JavaScript程序是由多个块(chunk)组成的,最常见的块就是function–函数.
我们把一段时间内,程序要执行的任务分为两部分:
1.执行部分(现在执行的),2.等待部分(剩下的将来要执行的).而我们面临的问题是,当现在执行部分执行完后,程序并不是严格地立马去完成等待部分.换句话就是,这些块是异步执行的.我们不会像预期的那样阻塞地完成一个接一个的任务.

例如:


//ajax是某些JavaScript框架(如:jQurey)中实现Ajax的函数

let data = ajax( "http://some.url.1" );


//控制台输出data内容

console.log(data)

如果运行这段JavaScript代码会发现,打印出来的data通常没有我们想要的ajax请求结果.
这是因为
,Ajax请求并不是同步(synchronously,相对于异步asynchronously)完成的,当执行console.log()的时候,我们想要的data还没有返回.我们想要的其实是ajax(...)函数能够阻塞,一直到请求结果返回,最简单的解决方法就是回调(callback).


//回调方式的一个示例,具体回调方式根据具体来定.

ajax( "http://some.url.1", function myCallbackFunction(data){


console.log( data );


} );


这时我们会发现,data就是我们想要的了.
注意:我们是可以同步地请求
Ajax的,比如:jQurey中的ajax()async: false加入设置.但是这样做的后果就是浏览器的UI操作(按钮,滚动等)以及用户交互等都会被阻塞等待锁死.我们应该避免这种情况,一团乱麻的回调函数也不应成为使用同步Ajax的理由.

记下来我们再考虑另一个例子帮助理解:

function now() {

return 21;

}


function later() {

answer = answer * 2;

console.log( "answer:", answer );

}


var answer = now();


setTimeout( later, 1000 ); // answer: 42


我们再用刚才的思路去理解这个程序:分为两个部分:执行部分,等待部分.

执行部分是:

//回调方式的一个示例,具体回调方式根据具体来定.

ajax( "http://some.url.1", function myCallbackFunction(data){


console.log( data );


} );


等待部分就是later()中的内容:

answer = answer * 2;

console.log( "answer:", answer );



执行部分会立刻执行,而setTimeout(...)会设定一个事件(timeout事件),在1000ms后执行later().就像这样,每当我们在function中写一段代码,并让它在事件(timer,鼠标事件,Ajax响应等)响应后执行,我们就创造了一个等待部分,也就是在程序中使用了异步.

Event Loop

    虽然我们在这里谈异步,但是,直到ES6*,JavaScript本身并没有内置异步的概念.听起来很震惊,但事实确实是这样的.我们会问:那我们讨论的异步是怎么实现的呢??
我们都知道的是
JavaScript引擎从来不是独立执行,总要依赖于一个环境,比如,我们最熟悉的web浏览器.以及服务器上的Node.js.这些环境会用一个机制来随时间使用JavaScript引擎处理我们的多个程序块,这个机制我们管它叫Event Loop.
换句话说,
JavaScript引擎并不知道什么时候执行,而是被执行环境的线程来安排处理哪些程序块,执行环境根据事件来调度JavaScript引擎处理.
那么什么是
Event Loop呢?
我们通过一段伪代码来了解它的概念:

//eventLoop是事件排成的先进先出的队列(queue)

var eventLoop = [ ];

var event;


while(true) {

// 处理完一个事件

if (eventLoop.length > 0) {

// 获取队列中的下个动作

event = eventLoop.shift();


// 处理刚才取出的动作

try {

event();

}

catch (err) {

reportError(err);

}

}

}


    我们通过这段伪代码大体了解它的机制.我们有一个循环,循环的每一个迭代中,如果在等待队列中存在事件,就会被取出并处理,event()就是各种回调函数.
因此,到这儿我们就可以明白了,
setTimeout(..)不是把设定好的回调函数安排到event loop中,而是将一个计时器(timer)安排在event loop中,当计时器到期,执行环境将回调推入event loop,这样,在将来某个时间会被取出并执行.
假如,现在
event loop中已经存在20个等待的成员,那么这个回调就应该等待,通常没有方法能将他移动到队列头部,让他立马执行.这样就产生了,哪怕用了setTimeout(..),指定的回调并不会在指定时间后立即执行的现象,当然也不会提前,至于是否要等待,等待多久,要根据具体情况来说.

注意:之所以说是”直到ES6”,是因为ES6引入了Promise机制,ES6通过Promiseevent loop的工作机制纳入到了JavaScript引擎的工作范围,而不只是执行环境的工作.关于Promise以后有机会再谈.

并行

    有一个常见的现象就是,人们经常把”异步”和”并行”混为一谈,其实他们大不相同.”异步”,指的是执行部分和等待部分中间有时间差,并不是立即执行.而并行则是指一起执行.
并行计算中最常见的单位是
进程(process)线程(thread),进程和线程之间可以是独立执行,也可以在一个处理器中,或者一台电脑中同时执行.通常,多个线程可以共享单个进程的内存.
相比之下
,event loop是将一个工作分解成多个任务,并组成队列串行执行,不能并行访问和更改共享的内存.它的并行性和”串行性”可以在不同线程下的event loop上体现(一个线程可以创立一个event loop,不同线程下的event loop具有并行性,单个event loop具有串行性).
并行地
执行线程异步地交错处理事件在粒度级别上有着很大的不同.线程是表达式操作级别,而异步是函数级别。

如有收获,请打赏作者

Javascript中的异步

作者:Illgo

博客地址:www.illgo.cn

通知:欢迎大家踊跃投稿,打赏归你哦!

——  End  ——

Javascript中的异步

本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

版权声明:程序员胖胖胖虎阿 发表于 2022年9月26日 下午9:24。
转载请注明:Javascript中的异步 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...