资讯专栏INFORMATION COLUMN

Javascript的异步和回调

CarlBenjamin / 1081人阅读

摘要:异步本质上应该就是多线程语言的产物。如果是多线程的异步,假死的应该是运行方法的线程,而方法仍然会按预期打印出。当然了,按我个人的理解,应该说是是的回调函数。

引子

每个故事都有由来。前两天在看 gulp 的时候,看到了它有个 promise 的玩意儿,然后的然后,这两天就掉进了 javascript 的异步和回调的坑里面去了。
其间搜索了 javascript promise,看到了一堆好文章。大概给个 List 吧。

https://software.intel.com/zh-cn/articles/asynchronized-javascript-pro...

http://stackoverflow.com/questions/7104474/how-does-asynchronous-javas...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Glob...

http://www.ruanyifeng.com/blog/2012/12/asynchronous_javascript.html

http://krasimirtsonev.com/blog/article/7-lines-JavaScript-library-for-...

http://segmentfault.com/q/1010000000140970

http://www.alloyteam.com/2014/05/javascript-promise-mode/

看得昏天黑地,大概也理清楚了一点,做个小总结。

一些概念

上面这些文章写得都挺好,但大部分都是上来直接说怎么异步回调,js的异步有哪些方法。这适合高级选手。我刚开始连啥是异步,啥是回调都不太清楚,这些方法自然也比较难理解。所以还是打好基础,先弄清楚异步、回调这些基本概念比较好。

同步与异步

先看个例子。

javascriptfoo();
bar();

程序运行一般是同步的(synchronous),即按照书写的顺序执行。在上述例子中,bar 方法会在 foo 方法执行完之后,再执行。

异步(asynchronous)与同步相对,即在前一个方法未执行完时,就开始运行后一个方法。在上述例子中,先执行 foo 方法,foo 方法没执行完,就开始执行 bar 方法。

总而言之,同步就是顺序执行,异步就是不完全按顺序执行。

异步的好处

从异步的概念中可以发现,程序异步运行,可以提高程序运行的效率,不必等一个程序跑完,再跑下一个程序,特别当这两个程序是无关的时候。两个程序在一定时间内,可以是同时运行的。写服务器的时候应该会碰到很多这样的例子。可以想象,如果服务器的程序都是同步的,那并发什么的就不存在了吧。

阻塞与非阻塞

这一点是我自己简单的理解。

阻塞就是说一个程序没运行完,它后面的程序是无法运行的。

非阻塞则相反,一个程序如果因为各种原因(网络、代码量等)没运行完的时候,其他的程序也是可以继续运行的。

单线程与多线程

这一点也是我自己的简单理解。

单线程是指程序运行只有一个通道,不同的方法需要排队执行。

而很多语言都可以提供多线程的功能,相当于开了几个通道运行程序,使得程序可以在不同的线程中运行,不会相互影响。

多线程、非阻塞、异步

从上述基本概念中可以发现,异步如果发生在多线程语言中,会十分自然且符合逻辑。异步本质上应该就是多线程语言的产物。因为只有在多线程语言中才能够实现程序之间相互不干扰,不产生阻塞。

JS 中的异步

有了上面的一些基本概念,那么下面来说说正题,JS中的异步。
我们都知道 JS 是一个单线程的语言,永远只有一个通道在运行程序。那么既然它是个单线程又如何会有异步呢?
JS 中所谓的异步,应该被称为伪异步(pseudo asynchronous)。这是因为 JS 语言中的异步,会产生阻塞,并会相互干扰。

模拟 JS 中异步的方法 —— setTimeout

我们来看一下 setTimeout 如何模拟 JS 中的异步。

javascriptvar foo = function(){
    console.log("foo begins");
    setTimeout(function(){
        console.log("foo finishes");
    },1000);
};
var bar = function(){
    console.log("bar executed");  
}
foo();
bar();

上述过程执行的时候,会打印出

  

foo begins
bar executed
foo finishes

所以,在上述代码块中,在前一方法(foo)执行时,后一方法(bar)也可以执行。符合异步的基本概念,程序并不按顺序执行。
说是模拟是因为,你可以把 console.log("foo begins"); 理解成会运行 1 秒的一个代码行,运行完后,会跳出foo finishes。而中间这 1 秒运行的时候,后面的 bar 方法也是可以运行的。这样就模拟了一个异步的效果。

JS 中异步的方法存在的问题 —— 阻塞与干扰

我们将上述代码块稍做修改

javascriptvar foo = function(){
    console.log("foo begins");
    setTimeout(function(){
        console.log("foo finishes");
    },1000);
};
var bar = function(){

    while(){

    } 
}
foo();
bar();

你会发现 1 秒之后 foo finishes 并没有被打印出来。这是因为 bar 方法是个死循环,使得 js 引擎假死,导致了 foo 方法也没有被运行完。如果是多线程的异步,假死的应该是运行 bar 方法的线程,而 foo 方法仍然会按预期打印出 foo finishes。当然了,其实这个死循环也只是模拟 bar 方法块程序运行的时间将很长。实际上,如果 bar 方法运行的时间超过了 1 秒,比方说是 5 秒,那么 foo finishes 也将在 5 秒之后被打印出来。这个本质上取决于 JS 单线程程序块按队列执行的特性。
所以 JS 中的异步并不能像普通的异步一样,实现非阻塞和不干扰。

JS 中异步的一些实现方法

虽然 JS 中的异步有其先天的缺陷,但是这种异步的思想,仍然能被 JS 程序开发人员所借鉴。毕竟,异步是可以大大提高程序运行效率的。
也正是由于 JS 本身是单线程程序的关系,所以 JS 中异步的实现,并不能像其他语言一样,简单地多开个线程就可以解决。
目前我看的集中方法主要有回调、事件类方法、promise等。

回调

先说说回调是什么吧。
回调(callback)这种名词就跟函数(function)一样,乍一看是比较难懂的,至少我是这样的。
根据sf上这个问答的解释,可以明确,把一个函数作为参数传入到另一个函数中,那么这个作为参数的函数就叫做回调函数。如:

javascriptvar foo = function(callback){
    // foo method
    callback();
};
foo(bar);

其中,bar 就是一个回调函数。当然了,按我个人的理解,应该说是 bar 是 foo 的回调函数。

To be Continued

时间问题,具体的实现方式和理解还没好好看,日后再做细细梳理。上述理解如有偏颇,欢迎讨论指正。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91510.html

相关文章

  • javascript异步与promise

    摘要:到这里,我已经发出了一个请求买汉堡,启动了一次交易。但是做汉堡需要时间,我不能马上得到这个汉堡,收银员给我一个收据来代替汉堡。到这里,收据就是一个承诺保证我最后能得到汉堡。 同期异步系列文章推荐谈一谈javascript异步javascript异步中的回调javascript异步之Promise.all()、Promise.race()、Promise.finally()javascr...

    rollback 评论0 收藏0
  • 浅析JavaScript异步

    摘要:回调函数,一般在同步情境下是最后执行的,而在异步情境下有可能不执行,因为事件没有被触发或者条件不满足。同步方式请求异步同步请求当请求开始发送时,浏览器事件线程通知主线程,让线程发送数据请求,主线程收到 一直以来都知道JavaScript是一门单线程语言,在笔试过程中不断的遇到一些输出结果的问题,考量的是对异步编程掌握情况。一般被问到异步的时候脑子里第一反应就是Ajax,setTimse...

    Tangpj 评论0 收藏0
  • javascript异步回调

    摘要:如果你把函数的指针地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 同期异步系列文章推荐谈一谈javascript异步javascript异步与promisejavascript异步之Promise.all()、Promise.ra...

    WalkerXu 评论0 收藏0
  • JS 异步实现

    摘要:由于引擎同一时间只执行一段代码这是由单线程的性质决定的,所以每个代码块阻塞了其它异步事件的进行。这意味着浏览器将等待着一个新的异步事件发生。异步的任务执行的顺序是不固定的,主要看返回的速度。 我们经常说JS是单线程的,比如node.js研讨会上大家都说JS的特色之一是单线程的,这样使JS更简单明了,可是大家真的理解所谓JS的单线程机制吗?单线程时,基于事件的异步机制又该当如何,这些知识...

    sihai 评论0 收藏0
  • JavaScript异步基础

    摘要:异步回调被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。回调函数经常被用于继续执行一个异步完成后的操作,它们被称为异步回调。回调函数是事件循环回头调用到程序中的目标,队列处理到这个项目的时候会运行它。 唯一比不知道代码为什么崩溃更可怕的事情是,不知道为什么一开始它是工作的! 在 ECMA 规范的最近几次版本里不断有新成员加入,尤其在处理异步的问题...

    hidogs 评论0 收藏0
  • 异步

    摘要:在异步机制中,任务队列就是用来维护异步任务回调函数的队列。四对象对象是工作组提出的一种规范,目的是为异步编程提供统一接口。 异步 1.JavaScript单线程的理解 Javascript语言的执行环境是单线程(single thread)。所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。 2.JavaScript单线...

    goji 评论0 收藏0

发表评论

0条评论

CarlBenjamin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<