AJax技术

从JavaScript的事件循环到Promise

字号+ 作者:H5之家 来源:H5之家 2018-03-29 10:03 我要评论( )

海南蜘蛛资讯网为广大玩家提供最新、最全、最具特色的海南蜘蛛资讯,同时还有各种八卦奇闻趣事。看蜘蛛资讯,就来海南蜘蛛资讯网!

大话西游3西瓜_从JavaScript的事件循环到Promise

JS线程是单线程运行机制,就是自己按顺序做自己的事,浏览器线程用于交互和控制,JS可以操作DOM元素,

说起JS中的异步时,我们需要注意的是,JS中其实有两种异步,一种是基于浏览器的异步IO,比如Ajax,另外一种是基于计时方法setTimeout和setInterval的异步。

对于异步IO,比如ajax,写代码的时候都是顺序执行的,但是在真正处理请求的时候,有一个单独的浏览器线程来处理,并且在处理完成后会触发回调。这种情况下,参与异步过程的其实有2个线程主体,一个是javascript的主线程,另一个是浏览器线程。

熟悉Javascript的人都知道,Javascript内部有一个事件队珠海凤凰山火灾_蜘蛛资讯网列,所有的处理方法都在这个队列中,Javascript主线程就是轮询这个队列处理,这个好处是使得CPU永远是忙碌状态。这个机制和Windows中的消息泵是一样的,都是靠消息(事件)驱动,

对于setTimeout和setInterval来说,韩非的剑逆鳞_蜘蛛资讯网当js线程执行到该代码片段时,js主线程会重燃料油_蜘蛛资讯网根据所设定的时间,当设定的时间到期时,将设置的回调函数放到事件队列中,然后js主线程继续去执行下边的代码,当js线程执行完主线程上的代码之后,会去循环执行事件队列中的函数。至于setTimeout或者setInterval设定的执行时间在实际表现时会有一些偏差,普遍的一个解释为,当定时任务的时间到期时,本应该去执行该回调函数,但是这时js主线程可能还有任务在执行,或者是该回调函数再事件队列中排的比较靠后,就导致该回调函数执行时间与定时器设定时间不一致。

那么问题来了,什么是事件队列?

eventloop是一个用作队列的数组,eventloop是一个一直在循环执行的,循环的每一轮成为一个tick,在每一个tick中,如果队列中有等待事件,那么就会从队列中摘取下一个事件进行执行,这些事件就是我们之前的回调函数。现在ES6精确指定了事件循环的工作细节,这意味着在技术上将其纳入了JavaScript引擎的势力范围,而不只是由宿主环境决定了,主要的一个原因是ES6中promise的引入。

var eventloop = [] var event; while(true){ if(eventloop.length>0){ //拿到队列中的下一个事件 event = eventloop.shift(); //现在执行下一个事件 try{ event(); }catch(e){ reportError(e); } } }

在浏览器端,setTimeout中的最小时间间隔是W3C在HTML标准中规定,规定要求低于4ms的时间间隔算为4ms。

任何时候,只要把一陆少的暖婚新妻最新_蜘蛛资讯网个代码包装成一个函数,并指定它在响应某个事件时执行,你就是在代码中创建了一个将来执行的模块,也由此在这个程序中引入了异步机制。

js引擎并不是独立运行的,它运行在宿主环境中,就是我们所看到的Web浏览器,当然,随着js的发展,包括最近的Node,便是给js提供了一个在服务器端运行的环境。并且现在的js还嵌入到了机器人到电灯泡的各种各样的设配中。

但是这些所有的环境都有一个共同的“点”,即为都提供了一种机制来处理程序中的多个块的执行,且执行每个块时调用JavaScript引擎,这种机制被称为事件循环。

js引擎本身并没有时间的概念,只是一个按需要执行JavaScript任意代码片段的环境。

对于js中的回调,我们最常见的就是链式回调和嵌套回调

我们经常再ajax中嵌套ajax调用然后再嵌套ajax调用,这就是回调地狱,回调最大的问题就是控制反转,它会导致信任链的完全断裂,为了解决回调中的控制反转问题,有些API提供了分离回调(一个用于成功通知,一个用于失败通知),例如ajax中的success函数和failure函数,这种情况下,API的出错处理函数failure()常常是可以省略的,如果没有提供的话,就是假定这个错误可以吞掉。

还有一种回调模式叫做“error-first"风格,其中回调的第一个参数保留用作错误对象,如果成功的话,这个参数就会被清空/置假。

回调函数是JavaScript异步的基础单元,但是随着JavaScript越来越成熟,对于异步领域的发展,回调已经不够用了。

Promise

Promise 是异步编程中的一种解决方案,最早由社区提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

Promise是一种封装和组合未来值的易于复用的机制。一种在异步任务中作为两个或更多步骤的流程控制机制,时序上的this-then-that. 假定调用一个函数foo(),我们并不需要去关心foo中的更多细节,这个函数可能立即完成任务,也可能过一段时间才去完成。对于我们来讲,我们只需要知道foo()什么时候完成任务,这样我们就可以去继续执行下一个任务了,在传统的方法中,我们回去选择监听这个函数的完成度,当它完成时,通过回调函数通知我们,这时候通知我们就是执行foo中的回调,但是使用promise时,我们要做的是侦听来自foo的事件,然后在得到通知的时候,根据情况而定。

其中一个重要的好出就是,机器人总动员2电影_蜘蛛资讯网我们可以把这个事件中的侦听对象提供给代码中多个独立的部分,在foo()完成的时候,他们都可以独立的得到通知:

var evt = foo(); //让bar()侦听foo()的完成 bar(evt); //让baz()侦听foo()的完成 baz(evt);

上边的例子中,bar和baz中不需要去知道或者关注foo中的实现细节。而且foo也不需要去关注baz和bar中的实现细节。

同样的道理,在promise中,前面的代码片段会让foo()创建并返回一个Promise实例,而且在这个Promise会被传递到bar()和baz()中。所以本质上,promise就是某个函数返回的对象。你可以把回调函数绑定再这个对象上,而不是把回调函数当成参数传进函数。

const promise = doSomething(); promsie.then(successCallback,failureCallback){ }

当然啦,promise不像旧式函数将回调函数传递到两个处理函数中,而且会有一个优点:

但是,Promise最直接的好出就是链式调用。

doSomething().then(function(result) { return doSomethingElse(result); }) .then(function(newResult) { return doThirdThing(newResult); }) .then(function(finalResult) { console.log("Got the final result: " + finalResult); }) .catch(failureCallback);

并且在一个失败操作之后还可以继续使用链式操作,即使链式中的一个动作失败之后还能有助于新的动作继续完成。

在调用Promise中的resolve()和reject()函数时如果带有参数,那么他们的参数会被传递给回调函数。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
网友点评