一. 什么是异步和同步
-
同步:如果能直接拿到结果,那就是同步。
比如:你去医院窗口挂号,目的是拿到号,你在拿到号之前是不会离开窗口的。总之,不拿到结果就不离开。对JS来说,就是,不执行完这一句代码,就一直停在这,不往下执行。
-
异步:如果不能直接拿到结果,就是异步。
比如:在餐厅门口等位。拿到号码之后,因为前边排队的人太多,不能马上吃饭,也就是不能直接得到结果。可以拿到号去逛街,做点别的事。
那什么时候才能真正吃饭呢?(拿到结果有两种方式)
- 你可以每十分钟自己去餐厅门口问一下,到几号了。(轮询)
- 你也可以留下电话号码,等轮到你了,餐厅给你打电话通知你可以去吃饭了。(回调)
-
异步举例:AJAX
request.send() 发送请求之后,不能直接拿到response。在send后马上打印出response,没有结果。但是,隔几毫秒再打印,就有结果。

同一个值,一开始拿不到结果,但是过一会就能拿到结果,就是异步。
那我怎么拿到结果呢?我写一个onreadystatechange函数,放在request对象上,等下载完成以后,浏览器回头调用这个函数。我就拿到了结果。这和我把电话留给餐厅的过程一样:我并不能马上吃饭,那餐厅怎么通知我可以吃饭了呢?我留一个电话号放在那,告诉餐厅,等结果出来了,给我打个电话(回头调用一下我写的这个函数)。
-
回调函数 callback
我自己写的函数,但自己不调用,而是给别人调用,这就是回调。(被别人调用的函数,是回调函数,是个名词。调这个回调函数,也是回调)
即:你自己写的函数,自己调用了,不是回调。
写给别人用的函数,就是回调。
回调,就是回头调用一下,将来的某个时刻,调用一下。
以AJAX为例,request.onreadystatechange 就是我写给浏览器调用的。因为send之后不能马上拿到结果,所以我写了个函数放在那,告诉浏览器,等结果出来了,你回头记得调用一下我这个函数。
f1是我自己写的函数,但是我没调用,我把f1作为参数传给了f2,f2调用了f1。这个f2就是别人。f1就是我写给f2用的回调函数。
回调可以把回调函数当作参数传给别人,把这个函数直接放到别人手里。也可以像request.onreadystatechange那样,把它放到request身上,让浏览器直接从request身上读。也就是说,不一定非要当作参数传给别人。
-
异步和回调的关系
异步是不能直接拿到结果,回调是我写一个函数放在那,等别人调用。
-
关联:异步需要用回调函数来通知结果。
让JS留一个函数地址给浏览器(留一个电话号码)。等异步任务完成时,浏览器回头调用一下这个函数地址(打电话)。同时,要把结果作为参数传给这个函数(电话里说可以吃饭了)。
-
区别:异步想要通知结果不一定要用回调,也可以轮询。只不过回调更常用。回调也不一定只用在异步任务里,也可以用在同步任务里。如arr.forEach()。即:异步和回调只是合作的关系。
二. 怎么区分函数是同步还是异步?
1. 不要把AJAX设为同步
首先,AJAX可以设置为同步的,request.open('GET','/5.josn',false),第三个参数,选择是否异步,默认是异步,fasle表示同步。但是,如果设为同步,在JS得到结果之前,啥都不干,只是等着,会使请求期间页面卡住。
2.

1. setTimeout举例

- q()里没有写return,也就是return undefined
- setTimeout里有return,即,真正的结果是由setTimeout返回的。
- 这两个return属于不同的函数
所以,这是一个异步函数/异步任务。所以,调用q,是拿不到结果的,为undefined。它需要一个回调函数,来通知结果。
我写一个回调函数f1,放在那,把这个函数地址留给q。当q拿到结果时,就回头调用一下f1,同时,在调用f1的时候,把结果作为参数传给f1。

q(x=>console.log(x))
再由于,x被传进去,又打印出来,所以还可以简化q(console.log)注意:console.log后边并没有括号,我没有调用它,只是把它作为参数传给了别人。
如果参数的个数不一致,就不能这样简化。
即,如果传进去(x,y),但是只打印一个x,就不能这样简化。有一个面试题:


