一、异步
如果能直接拿到结果就是同步。
比如:你在医院挂号。任务是拿到号,你只有拿到号,你才会离开
如果不能直接拿到结果就是异步。
比如:网红餐厅排队吃饭,人很多,你的任务是吃饭,只有吃到饭才能离开,那么如果排队人很多,比如给你了一个100号,前面有99人等待,那么你是不是就可以再等待的时候去逛街或者做别的。你可以在这个时间每10分钟去餐厅问一下到你没有(轮询),也可以用手机微信扫码接受通知(回调),知道你吃上饭。
在异AJXA为例,其实request.send()之后,并不能能直接拿到结果,不信可以console.log(request.response)试试,必须等到readyState变成4后,浏览器回头调用request.onreadystatechange函数才可以。
二、回调callback
回调函数是异步操作最基本的方法。简单来说,回调就是自己写了却不调用,给别人调用的函数
代码实例
function f1(){} function f2(fn){ fn() } f2(f1)
代码1:函数2调用函数1
f1
函数被声明,却没有被调用- 把
f1
函数当成参数传给f2
函数, f2
函数调用了f1
函数,所以f1
是回调
function f1(x){ console.log(x) } function f2(fn){ fn('你好') } f2(f1)
代码2:
fn('你好')
中的fn
就是f1
, fn('你好')
中的你好
会被赋值给参数x
那么思考一下最后的结果是打印出你好,你好来自于哪里,是不是f2调用并且给f1传递了一个参数,那么问下f2的运行结果是什么?(参数)
三、异步与回调的关系
关联
异步任务需要在得到结果时通知JS
来读取结果。等待通知的过程就是异步,通知JS
读取结果的过程就是回调。
具体实现就是让JS
编写留下函数地址给浏览器(留下电话号码),异步完成后浏览器调用该函数地址(拨打电话),同时把参数传给该函数(打电话通知顾客取那桌就餐),这个函数是用户写给浏览器调用的,所以是回调函数
区别
异步任务需要用到回调函数来通知结果
回调函数却不一定存在于异步任务中,同步任务中也可以用到回调函数,
例如array.forEach(n=>{console.log(n)})
,其中n=>{console.log(n)}
就是回调函数
四、如何判断是同步还是异步
异步
如果一个函数的返回值处于如下三种情况就是异步(暂时直说三种)
setTimeout
AJAX (即XMLHttpRequest)
AddEventListener
如果一个函数在这三个内部,就是异步
注意:AJAX
也可以设置为同步的,例如在request.open("get", "/style.css", false)
添加false
。但是在请求期间会让页面卡住,阻止用户其他操作。因此, 异步才是最佳选择。
五、摇骰子例子
例子总结(提前说)
异步任务不能拿到结果,所以需要传一个回调给异步任务。
异步任务完成时调用回调,调用的时候把结果作为参数传给回调函数
第一步
function 摇骰子(){ // 异步函数 setTimeout(()=>{ return parseInt(Math.random()*6)+1 },1000) //return undefined } const n = 摇骰子() console.log(n) // undefined
摇骰子()
没有写return
,所以返回return undefined
。箭头函数
返回真正的结果
第二步
function f1(x){console.log(x)} function 摇骰子(fn){ // 异步函数 setTimeout(()=>{ fn(parseInt(Math.random()*6)+1) },1000) //return undefined } 摇骰子(f1)
怎样拿到异步的结果?
使用回调。
首先声明函数,然后把函数地址传给摇骰子()
, 然后摇骰子()
得到结果后把结果作为参数传给f1()
第三步(代码简化)
function f1(x){console.log(x)} 摇骰子(f1) //简化1 摇骰子( x=>{console.log(x)}) // 简化 2 摇骰子(console.log)//最简
注意,如果参数个数不一致,就不能这样简化到最后一步。函数中一个参数x
和一个执行参数x
是一致的,简化成功。
例子
// 输入错误结果,简化失败 const array = ['1','2','3'] array.map(parseInt) // [1, NaN, NaN] // 正确运行 const array = ['1','2','3'] array.map((item, i, array) =>{ return parseInt(item) }
六、回调的弊端
1、在处理回调时代码不够规范,命名不规范
2、容易出现回调地狱
3、很难进行错误处理