快上网专注成都网站设计 成都网站制作 成都网站建设
成都网站建设公司服务热线:028-86922220

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

javascript同步的简单介绍

JAVASCRIPT 同步问题

//看你原先的代码 感觉不能实现你要的功能 就自己在你的基础上改了很多东西 ,如果感觉不行 就当我自己学习了

成都创新互联公司成立十余年来,这条路我们正越走越好,积累了技术与客户资源,形成了良好的口碑。为客户提供网站制作、做网站、网站策划、网页设计、域名申请、网络营销、VI设计、网站改版、漏洞修补等服务。网站是否美观、功能强大、用户体验好、性价比高、打开快等等,这些对于网站建设都非常重要,成都创新互联公司通过对建站技术性的掌握、对创意设计的研究为客户提供一站式互联网解决方案,携手广大客户,共同发展进步。

html

head

title现在开始倒计时/title

style

*{

font-size:12px;

}

/style

script

var TIME = 10; //给定的最大时间,可修改

var GUESS_TIME = 5;//给定的最大猜数字,可修改

var time = TIME, s;

var i, j = 1;// 记数

var normal = true;//是否是正常流程

var gamestart = false;//游戏是否已经开始

// 初始化所猜数字

function init() {

time = TIME;

i = Math.round(Math.random() * 10 + 1);

}

// 猜一下

function guess_start() {

var randnum = $('rettime').value;

if (gamestart) {

if (randnum randnum != '请输入数字1--10之间') {

if (j = GUESS_TIME) {

if (randnum == i) {

$('result').innerHTML += "br恭喜你,你猜对了" + i + "br"+ "你是第:" + j + "次,猜对的 ";

guess_over();

} else if (randnum i) {

$('result').innerHTML += "br你输入的数字太font color='red'大/font了 ";

} else {

$('result').innerHTML += "br你输入的数字太font color='blue'小/font了 ";

}

j++;

} else {

$('result').innerHTML += "br很遗憾你已经没有机会了!" + "这个数字是:" + i+ " ";

guess_over();

normal = false;

}

} else {

$('result').innerHTML += "br请输入你猜的数字!";

}

} else {

$('result').innerHTML += "br游戏还未开始!请点击'" + $('gamestrat').value + "'";

}

}

// 猜结束

function guess_over(game_failure) {

cl();

j = 0;

//重新开始

game_restart();

}

// 游戏开始

function game_start() {

init();

$('rettime').disabled = false;

gamestart = true;

// 倒计时开始

s = setInterval(retime, 1000);

}

//游戏重新开始重置为初始状态

function game_restart() {

reset();

}

// 倒计时结束

function cl() {

clearInterval(s);

}

// 游戏主要方法

function retime() {

if (time 0) {

$('gamestrat').value = '还剩' + (time 10 ? '0' + time : time) + "秒";

time--;

} else {

if (normal)

$('result').innerHTML += "br时间到了 ";

reset();

cl();

}

}

//重置为初始模式

function reset() {

$('gamestrat').value = '重新开始';

$('rettime').value = '请输入数字1--10之间';

$('rettime').disabled = true;

gamestart = false;

}

function $(id) {

return document.getElementById(id);

}

/script

/head

body

input type="button" id="gamestrat" value="开始游戏" onclick="game_start();"

input type="text" id="rettime" value="请输入数字1--10之间" disabled="true" onfocus="this.value=''" onkeyup="this.value=this.value.replace(/\D/,'');"

a href="javascript:void 0" onclick="guess_start()"猜一下/a

div id="result"/div

/body

/html

如何实现 javascript “同步”调用 app 代码

在 App 混合开发中,app 层向 js 层提供接口有两种方式,一种是同步接口,一种一异步接口(不清楚什么是同步的请看这里的讨论)。为了保证 web 流畅,大部分时候,我们应该使用异步接口,但是某些情况下,我们可能更需要同步接口。同步接口的好处在于,首先 js 可以通过返回值得到执行结果;其次,在混合式开发中,app 层导出的某些 api 按照语义就应该是同步的,否则会很奇怪——一个可能在 for 循环中使用的,执行非常快的接口,比如读写某个配置项,设计成异步会很奇怪。

那么如何向 js 层导出同步接口呢?

我们知道,在 Android 框架中,通过 WebView.addJavascriptInterface() 这个函数,可以将 java 接口导出到 js 层,并且这样导出的接口是同步接口。但是在 iOS 的 Cocoa 框架中,想导出同步接口却不容易,究其原因,是因为 UIWebView 和 WKWebView 没有 addJavascriptInterface 这样的功能。同时,Android 这个功能爆出过安全漏洞,那么,我们有没有别的方式实现同步调用呢?我们以 iOS UIWebView 为例提供一种实现,WKWebView 和 Android 也可以参考。

为了找到问题的关键,我们看一下 iOS 中实现 js 调用 app 的通行方法:

首先,自定义 UIWebViewDelegate,在函数 shouldStartLoadWithRequest:navigationType: 中拦截请求。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

- (BOOL) webView:(UIWebView* _Nonnull)webView

shouldStartLoadWithRequest:(NSURLRequest* _Nonnull)request

navigationType:(UIWebViewNavigationType)navigationType {

if ([request.HTTPMethod compare:@"GET" options:NSCaseInsensitiveSearch] != NSOrderedSame) {

// 不处理非 get 请求

return YES;

}

NSURL* url = request.URL;

if ([url.scheme isEqualToString:@'YourCustomProtocol']) {

return [self onMyRequest:request];

}

return YES;

}

这种做法实质上就是将函数调用命令转化为 url,通过请求的方式通知 app 层,其中 onMyRequest: 是自定义的 request 响应函数。为了发送请求,js 层要建立一个隐藏的 iframe 元素,每次发送请求时修改 iframe 元素的 src 属性,app 即可拦截到相应请求。

1

2

3

4

5

6

7

8

9

10

11

12

13

/**

* js 向 native 传递消息

* @method js_sendMessageToNativeAsync

* @memberof JSToNativeIOSPolyfill

* @public

* @param str {String} 消息字符串,由 HybridMessage 转换而来

*/

JSToNativeIOSPolyfill.prototype.js_sendMessageToNativeAsync = function (str) {

if (!this.ifr_) {

this._prepareIfr();

}

this.ifr_.src = 'YourCustomProtocol://__message_send__?msg=' + encodeURIComponent(str); }

当 app 执行完 js 调用的功能,执行结果无法直接返回,为了返回结果,普遍采用回调函数方式——js 层记录一个 callback,app 通过 UIWebView 的 stringByEvaluatingJavaScriptFromString 函数调用这个 callback(类似 jsonp 的机制)。

注意,这样封装的接口,天然是异步接口。因为 js_sendMessageToNativeAsync 这个函数会立即返回,不会等到执行结果发回来。

所以,我们要想办法把 js 代码“阻塞”住。

请回忆一下,js 中是用什么方法能把 UI 线程代码“阻塞”住,同时又不跑满 CPU?

1

2

3

4

var async = false;

var url = '';

var method = 'GET';brvar req = new XMLHttpRequest();br

req.open(method, url, async);brreq.send(null);

“同步”ajax(其实没这个词,ajax 内涵异步的意思)可以!在 baidu 的响应没返回之前,这段代码会一直阻塞。一般来说同步请求是不允许使用的,有导致 UI 卡顿的风险。但是在这里因为我们并不会真的去远端请求内容,所以不妨一用。

至此实现方式已经比较清楚了,梳理一下思路:

使用同步 XMLHttpRequest 配合特殊构造的 URL 通知 app层。

app 层拦截请求执行功能,将结果作为 Response 返回。

XMLHttpRequest.send() 返回,通过 status 和 responseText 得到结果。

那么,如何拦截请求呢?大家知道,UIWebViewDelegate 是不会拦截 XMLHttpRequest 请求的,但是 iOS 至少给了我们两个位置拦截这类请求——NSURLCache 和 NSURLProtocol。

一、NSURLCache 是 iOS 中用来实现自定义缓存的类,当你创建了自定义的 NSURLCache 子类对象,并将其设置为全局缓存管理器,所有的请求都会先到这里检查有无缓存(如果你没禁掉缓存的话)。我们可以借助这个性质拦截到接口调用请求,执行并返回数据。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

- (NSCachedURLResponse*) cachedResponseForRequest:(NSURLRequest *)request {

if ([request.HTTPMethod compare:@"GET" options:NSCaseInsensitiveSearch] != NSOrderedSame) {

// 只对 get 请求做自定义处理

return [super cachedResponseForRequest:request];

}

NSURL* url = request.URL;

NSString* path = url.path;

NSString* query = url.query;

if (path == nil || query == nil) {

return [super cachedResponseForRequest:request];

}

LOGF(@"url = %@, path = %@, query = %@", url, path, query);

if ([path isEqualToString:@"__env_get__"]) {

// 读环境变量

return [self getEnvValueByURL:url]; //*

} else if ([path isEqualToString:@"__env_set__"]) {

// 写环境变量

return [self setEnvValueByURL:url];

}

return [super cachedResponseForRequest:request];

}

注意注释有 * 号的一行,即是执行 app 接口,返回结果。这里的结果是一个 NSCachedResponse 对象,就不赘述了。

怎样用JS实现异步转同步

源起

小飞是一名刚入行前端不久的新人,因为进到了某个大公司,俨然成为了学弟学妹眼中'大神',大家遇到js问题都喜欢问他,这不,此时他的qq弹出了这样一条消息

"hi,大神在吗?我有个问题想问,现在我们的代码里面有这样的东西,可是得不到正确的返回结果

1234567

function getDataByAjax () {return $.ajax(...postParam)}var data = getDataByAjax()if (data) {   console.log(data.info)}

"哦,你这里是异步调用,不能直接获得返回值,你要把if语句写到回调函数中",小飞不假思索的说到,对于一个‘专业’的fe来说,这根本不是一个问题。

“可是我希望只是改造getDataByAjax这个方法,让后面的代码成立。”

“研究这个没有意义,异步是js的精髓,同步的话会阻塞js调用,超级慢的,但是你要一再坚持的话,用async:true就好了”

“不愧是大神,我回去立刻试一试,么么哒”

两天后,她哭丧着脸登上了qq

“试了一下你的方法,但是根本行不通,哭~~”

“别急,我看看你这个postParam的参数行吗”

123456

{...   dataType: 'jsonp',async: true...}

"这是一个jsonp请求啊,老掉牙的东西了,,jsonp请求是没有办法同步的"

“我知道jsonp请求的原理是通过script标签实现的,但是,你看,script也是支持同步的呀,你看tags/attscriptasync.asp”

“额,那可能是jquery没有实现吧,哈哈”

“大神,你能帮我实现一个jsonp的同步调用方式嘛,拜托了(星星眼)”

虽然他有点奇怪jquery为什么没有实现,但是既然w3school的标准摆在那里,码两行代码又没什么,

1234567891011121314

export const loadJsonpSync = (url) = {var result; window.callback1 = (data) = (result = data)let head = window.document.getElementsByTagName('head')[0]let js = window.document.createElement('script') js.setAttribute('type', 'text/javascript') js.setAttribute('async', 'sync')  // 这句显式声明强调src不是按照异步方式调用的 js.setAttribute('src', url) head.appendChild(js)return result}

额,运行起来结果竟然是undefined!w3cshool的文档竟然也不准,还权威呢,我看也不怎么着,小飞暗自想到。

“刚才试了一下,w3school文档上写的有问题,这个异步属性根本就是错的”

“可是我刚还试过一次这个,我确认是好的呀”

12

script src="loop50000 put('frist').js"/scriptscript src="put('second').js"/script

(有兴趣的同学可以实现以下两个js,并且加上async的标签进行尝试。)

“这个,我就搞不清楚了”,小飞讪讪的说到

对方已离线

抽象

关于这个问题,相信不只是小飞,很多人都难以解答。为什么ajax可以做到同步,但jsonp不行,推广到nodejs上,为什么readFile也可以做到同步(readFileSync),但有的库却不行。

(至于script的async选项我们暂时避而不谈,是因为现在的知识维度暂时还不够,但是不要着急,下文中会给出明确的解释)

现在,让我们以计算机科学的角度抽象这个问题:

我们是否可以将异步代码转化为同步代码呢?(ASYNCCALL = SYNCCALL)

既然是抽象问题,那么我们就可以不从工程角度/性能角度/实现语言等等等方面来看(同步比异步效率低下),每增加一个维度,复杂程度将以几何爆炸般增长下去。

首先,我们来明确一点,==在计算机科学领域==同步和异步的定义

同步(英语:Synchronization),指对在一个系统中所发生的事件(event)之间进行协调,在时间上出现一致性与统一化的现象。在系统中进行同步,也被称为及时(in time)、同步化的(synchronous、in sync)。--摘自百度百科

异步的概念和同步相对。即时间不一致,不统一

明确了这一点,我们可以借助甘特图来表示同步和异步

其中t1和t2是同步的,t1和t3是异步的。

答案就在操作系统原理的大学教材上,我们有自旋锁,信号量来解决问题,伪代码如下

1234567891011121314151617

spinLock () {// 自旋锁  fork Wait 3000 unlock() //开启一个异步线程,等待三秒后执行解锁动作  loop until unlock // 不断进行空循环直到解锁动作Put ‘unlock’} //pv原语,当信号量为假时立即执行下一步,同时将信号量置真//反之将当前执行栈挂起,置入等待唤醒队列//uv原语,将信号量置为假,并从等待唤醒队列中唤醒一个执行栈Semaphore () {  pv()  fork Wait 3000 uv()  pv()  uv()Put 'unlock'}

很好,至此都可以在操作系统原理的教材上翻到答案。于是我们在此基础上添加约束条件

仅仅依赖于js本身,我们是否可以将异步代码转化为同步代码呢?(ASYNCCALL = SYNCCALL)

论证

带着这个问题,我们翻看一下jquery的源码

src/ajax/xhr.js#L42

可以看出, ajax的同步机制本质上是由XMLHttpRequest实现的,而非js原生实现。

同样的道理,我们再翻看一下nodejs的源码

lib/fs.js#L550

从readFileSync-tryReadSync-readSync一路追下去,会追到一个c++ binding, node_file.cc#L1167

123456

if (req-IsObject()) {   ASYNC_CALL(read, req, UTF8, fd, uvbuf, 1, pos);} else {   SYNC_CALL(read, 0, fd, uvbuf, 1, pos)   args.GetReturnValue().Set(SYNC_RESULT);}

同步的奥妙在于c++的宏定义上,这是一种借由c++来实现的底层同步方式。

观察了这两种最广泛的异步转同步式调用,我们发现均没有采用js来实现。

似乎从现象层面上来看js无法原生支持,但是这还不够,我们探究在js语义下上面的自旋锁/信号量的特性模拟实现(我知道你们一定会嗤之以鼻,==js本身就是单线程的,只是模拟了多线程的特性== 我无比赞同这句话,所以这里用的不是实现,而是特性模拟实现),另外,由于settimeout具有fork相似的异步执行特性,所以我们用setitmeout暂时代替fork

自旋锁

1.第一个实现版本

1234567

var lock = truesetTimeout(function () {lock = false}, 5000) while(lock);console.log('unlock')

我们预期在5000ms后执行unlock语句,但是悲剧的是,整个chrome进程僵死掉了。

为了解释清楚这个问题,我们读一下阮一峰老师的event loop模型

event-loop.html

看样子咱们已经清楚的了解了event loop这个js运行顺序的本质(同步执行代码立即执行,异步代码入等待队列),那么,我们可以基于此给出js vm的调度实现(eventloop的一种实现),当然,咱们为了解释自旋锁失败只需要模拟异步操作, 同步操作,和循环就好

123456789101112131415161718192021222324

//taskQueue:任务队列//runPart:当前正在执行的任务(同步指令集)//instruct: 正在执行的指令 function eventloop (taskQueue) {while(runPart = taskQueue.shift()) {while(instruct = runPart.shift()) {const { type, act, codePart } = instructswitch(type) {case 'SYNC':         console.log(act)if (act === 'loop')           runPart.unshift({             act: 'loop',             type: 'SYNC'})breakcase 'ASYNC':         taskQueue.push(codePart)break}}}}

然后转化我们的第一个版本自旋锁

1234567891011121314151617181920

let taskQueue = [[{act: 'var lock = true', type: 'SYNC'}, //var lock = true{       act: 'setTimeout',       type: 'ASYNC',       codePart: [{act: 'lock = false', type: 'SYNC'}]}, // setTimeout(function () { lock = false }, 5000)/*{       act: 'loop',       type: 'SYNC'   },*/ // while(lock);{       act: 'console.log(\'sync\')',       type: 'SYNC'} // console.log('unlock')]]em id="__mceDel" /em

测试一下,符合evnet loop的定义,然后放开注释,我们成功的让loop block住了整个执行过程,lock = false永远也没有机会执行!!!

(真实的调度机制远比这个复杂的多得多的,有兴趣的可以看看webkit~~~的jscore的实现哈)

知道了原理,我们就来手动的改进这部分代码

2.改进的代码

12345678910111213141516

var lock = truesetTimeout(function () {lock = false   console.log('unlock')}, 5000) function sleep() {var i = 5000while(i--);} var foo = () = setTimeout(function () {   sleep()lock foo()})foo()

这个版本的改进我们对while(true);做了切块的动作,实际上这种技巧被广泛的应用到改善页面体验的方面,所以,有些人因为时序无法预知而抗拒使用settimeout这种想法是错误的!

6996528,

小测验1: 改写eventloop和taskQueue,使它支持改进后的代码

可是,如果把代码最后的foo() 变成 foo() console.log('wait5sdo'),

我们的代码依然没有成功,why

注意看我们标红的地方,如果你完成了小测验1,就会得到和这张图一致的顺序

==同步执行的代码片段必然在异步之前。==

所以,无论从理论还是实际出发,我们都不得不承认,在js中,把异步方法改成同步方法这个命题是水月镜花

哦对了,最后还需要解释一下最开始我们埋下的坑, 为什么jsonp中的async没有生效,现在解释起来真的是相当轻松,即document.appendChild的动作是交由dom渲染线程完成的,所谓的async阻塞的是dom的解析,而非js引擎的阻塞。实际上,在async获取资源后,与js引擎的交互依旧是push taskQueue的动作,也就是我们所说的async call

推荐阅读: 关于dom解析请大家参考webkit技术内幕第九章资源加载部分

峰回路转

相信很多新潮的同学已经开始运用切了async/await语法,在下面的语法中,getAjax1和console之间的具有同步的特性

1234

async function () {var data = await getAjax1()   console.log(data)}

讲完了event loop和异步的本质,我们来重新审视一下async/await。

老天,这段代码亲手推翻了==同步执行的代码片段必然在异步之前。== 的黄金定律!

惊不惊喜,意不意外,这在我们的模型里如同三体里的质子一样的存在。我们重新审视了一遍上面的模型,实在找不到漏洞,找不到任何可以推翻的点,所以真的必须承认,async/await绝对是一个超级神奇的魔法。

到这里来看我们不得不暂时放弃前面的推论,从async/await本身来看这个问题

相信很多人都会说,async/await是CO的语法糖,CO又是generator/promise的语法糖,好的,那我们不妨去掉这层语法糖,来看看这种代码的本质, 关于CO,读的人太多了,我实在不好老生常谈,可以看看这篇文章,咱们就直接绕过去了,这里给出一个简易的实现

/5800210.html

1234567891011121314151617181920

function wrap(wait) {var iter iter = wait()const f = () = {const { value } = iter.next()   value value.then(f)} f()} function *wait() {var p = () = new Promise(resolve = {     setTimeout(() = resolve(), 3000)})yield p() console.log('unlock1')yield p() console.log('unlock2') console.log('it\'s sync!!')}

终于,我们发现了问题的关键,如果单纯的看wait生成器(注意,不是普通的函数),是不是觉得非常眼熟。这就是我们最开始提出的spinlock伪代码!!!

这个已经被我们完完全全的否定过了,js不可能存在自旋锁,事出反常必有妖,是的,yield和*就是表演async/await魔法的妖精。

generator和yield字面上含义。Gennerator叫做生成器,yield这块ruby,python,js等各种语言界争议很大,但是大多数人对于‘让权’这个概念是认同的(以前看到过maillist上面的争论,但是具体的内容已经找不到了)

扩展阅读---ruby元编程 闭包章节yield(ruby语义下的yield)

所谓让权,是指cpu在执行时让出使用权利,操作系统的角度来看就是‘挂起’原语,在eventloop的语义下,似乎是暂存起当时正在执行的代码块(在我们的eventloop里面对应runPart),然后顺序的执行下一个程序块。

我们可以修改eventloop来实现让权机制

小测验2 修改eventloop使之支持yield原语

至此,通过修改eventloop模型固然可以解决问题,但是,这并不能被称之为魔法。

和谐共存的世界

实际上通过babel,我们可以轻松的降级使用yield,(在es5的世界使用让权的概念!!)

看似不可能的事情,现在,让我们捡起曾经论证过的

==同步执行的代码片段必然在异步之前。== 这个定理,在此基础上进行进行逆否转化

==在异步代码执行之后的代码必然不是同步执行的(异步的)。==

这是一个圈子里人尽皆知的话,但直到现在他才变得有说服力(我们绕了一个好长的圈子)

现在,让我们允许使用callback,不使用generator/yield的情况下完成一个wait generator相同的功能!!!

1234567891011121314151617181920

function wait() {const p = () = ({value: new Promise(resolve = setTimeout(() = resolve(), 3000))})let state = {next: () = {       state.next = programPartreturn p()}}function programPart() {     console.log('unlocked1')     state.next = programPart2return p()}function programPart2() {     console.log('unlocked2')     console.log('it\'s sync!!')return {value: void 0}}return state}

太棒了,我们成功的完成了generator到function的转化(虽然成本高昂),同时,这段代码本身也解释清楚了generator的本质,高阶函数,片段生成器,或者直接叫做函数生成器!这和scip上的翻译完全一致,同时拥有自己的状态(有限状态机)

推荐阅读 计算机程序的构造和解释 第一章generator部分

小测验3 实际上我们提供的解决方式存在缺陷,请从作用域角度谈谈

其实,在不知不觉中,我们已经重新发明了计算机科学中大名鼎鼎的CPS变换

Continuation-passing_style

最后的最后,容我向大家介绍一下facebook的CPS自动变换工具--regenerator。他在我们的基础上修正了作用域的缺陷,让generator在es5的世界里自然优雅。我们向facebook脱帽致敬!!egenerator

后记

同步异步 可以说是整个圈子里面最喜欢谈论的问题,但是,谈来谈去,似乎绝大多数变成了所谓的‘约定俗称’,大家意味追求新技术的同时,却并不关心新技术是如何在老技术上传承发展的,知其然而不知其所以然,人云亦云的写着似是而非的js。

==技术,不应该浮躁==

PS: 最大的功劳不是CO,也不是babel。regenerator的出现比babel早几个月,而且最初的实现是基于esprima/recast的,关于resprima/recast,国内似乎了解的并不多,其实在babel刚刚诞生之际, esprima/esprima-fb/acron 以及recast/jstransfrom/babel-generator几大族系围绕着react产生过一场激烈的斗争,或许将来的某一天,我会再从实现细节上谈一谈为什么babel笑到了最后~~~~

javascript同步和异步处理数组的几种方法

concat()连接两个或更多的数组,并返回结果。

join()把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。

pop()删除并返回数组的最后一个元素

push()向数组的末尾添加一个或更多元素,并返回新的长度。

reverse()颠倒数组中元素的顺序。

JavaScript 中,用 async + await 和直接同步方式执行有什么区别

async await都是通过promise 来实现,可以同时并行多个任务

直接同步方式的话

假设你要得到10本书的JSON文件采取同步方式,那么是等待书本一个一个的获取

但是如果是async await的话可以直接类似

async function book(u){

let data =  await getJson(u)

$dom.parse(data)

}

lz可以跑下下列代码

var hold = function () {

return new Promise(function (resolve, reject) {

resolve();

})

};

async function count(i){

await hold()

console.log(i)

}

for(var i = 0 ;i  10 ; i++)

 count(i);

console.log("run")

实际上是run 先跑

javascript同步和异步的区别与实现方式

javascript语言是单线程机制。所谓单线程就是按次序执行,执行完一个任务再执行下一个。

对于浏览器来说,也就是无法在渲染页面的同时执行代码。

单线程机制的优点在于实现起来较为简单,运行环境相对简单。缺点在于,如果中间有任务需要响应时间过长,经常会导致

页面加载错误或者浏览器无响应的状况。这就是所谓的“同步模式”,程序执行顺序与任务排列顺序一致。对于浏览器来说,

同步模式效率较低,耗时长的任务都应该使用异步模式;而在服务器端,异步模式则是唯一的模式,如果采用同步模式个人认为

服务器很快就会出现12306在高峰期的表现。。。。

异步模式的四种方式:

1.回调函数callback

所谓回调函数,就是将函数作为参数传到需要回调的函数内部再执行。

典型的例子就是发送ajax请求。例如:

$.ajax({

async: false,

cache: false,

dataType: 'json',

url: "url",

success: function(data) {

console.log('success');

},

error: function(data) {

console.log('error');

}

})

当发送ajax请求后,等待回应的过程不会堵塞程序运行,耗时的操作相当于延后执行。

回调函数的优点在于简单,容易理解,但是可读性较差,耦合度较高,不易于维护。

2.事件驱动

javascript可以称之为是基于对象的语言,而基于对象的基本特征就是事件驱动(Event-Driven)。

事件驱动,指的是由鼠标和热键的动作引发的一连串的程序操作。

例如,为页面上的某个

$('#btn').onclick(function(){

console.log('click button');

});

绑定事件相当于在元素上进行监听,是否执行注册的事件代码取决于事件是否发生。

优点在于容易理解,一个元素上可以绑定多个事件,有利于实现模块化;但是缺点在于称为事件驱动的模型后,流程不清晰。

3.发布/订阅

发布订阅模式(publish-subscribe pattern)又称为观察者模式(Observer pattern)。

该模式中,有两类对象:观察者和目标对象。目标对象中存在着一份观察者的列表,当目标对象

的状态发生改变时,主动通知观察者,从而建立一种发布/订阅的关系。

jquery有相关的插件,在这不是重点不细说了。。。。回头写个实现贴上来

4.promise模式

promise对象是CommonJS工作组提供的一种规范,用于异步编程的统一接口。

promise对象通常实现一种then的方法,用来在注册状态发生改变时作为对应的回调函数。

promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS

Promise/A

标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler,

rejectedHandler); 。resolvedHandler

回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。

Jquery在1.5的版本中引入了一个新的概念叫Deferred,就是CommonJS promise A标准的一种衍生。可以在jQuery中创建

$.Deferref的对象。同时也对发送ajax请求以及数据类型有了新的修改,参考JQuery API。

除了以上四种,javascript中还可以利用各种函数模拟异步方式,更有诡异的诸如用同步调用异步的case

只能用team里同事形容java和javascript的一句话作为结尾:

“写java像在高速路上开车,写javascript像在草原上开车”-------------以此来形容javascript这种无类型的语言有多自由

but,如果草原上都是坑。


文章名称:javascript同步的简单介绍
本文URL:http://6mz.cn/article/dscoohs.html

其他资讯