异步与同步
同步:能直接拿到结果的。就比如说你在医院挂号,你要拿到号才会离开。同步任务可能消耗几毫秒到几十毫秒不等,总之是要拿到结果才行。
异步:不能直接拿到结果的。就比如说你在餐厅等号,拿到号你可以临时离开去干别的事,你可以每隔一段时间来问一下(轮询),也可以通过手机来得到消息(回调)。
回调(callback)
写给别人用的函数就是回调。假设request.onreadystatechange就是写给浏览器调用的,意思就是浏览器回头调用一下这个函数。写了却不调用,给别人调用的函数,就是回调。
function f1(){}
function f2(fn){
fn()
}
f2(f1)
上述是把f1传给了f2,f2调用了f1,没有调用f1,所以f1是写给f2调用的函数,即f1就是回调。
异步与回调(callback)的关系
- 异步任务需要用到回调函数来通知结果。
- 但是回调函数不一定只用在异步任务里面,回调可以用到同步任务里array.forEach(n=>console.log(n))就是同步回调。
- 异步常常会用到回调,但不一定要用到回调。异步不只有回调,还有轮询。
判断异步与同步
异步:
setTimeout
AJAX(即XMLHttpRequest)
AddEventListener
虽然AJAX也可以同步,但是不要将AJAX设置为同步的,因为将AJAC设置为同步,这样做会使请求期间页面卡住。
举个异步的例子:
function yao(){
setTimeout(()=>{
return parseInt(Math.random() * 6)+1
},1000)
}
分析:yao()没有return,箭头函数里面有return,这里返回的才是真正的结果, 这里的箭头函数现在并没有被立即执行,所以这是一个异步任务/函数。
yao()返回的是一个undefine值,那么我们要怎么样才能获取到异步结果呢? 我们可以利用回调,写一个函数,然后把这个函数地址给它,
function yao(fn){
setTimeout(()=>{
fn(parseInt(Math.random()*6)+1))
},1000)
}
yao(console.log) //function f1(x){console.log(x)}; yao(f1)的缩写
两个异步结果
在AJAX中,我们回遇到成功和失败的两个异步任务结果,我们可以用以下两种方法
方法一,回调接受两个参数,一个是成功参数,一个是失败参数。
fs.readFile('/1.txt', (error, data)=>{
if(error){console.log('失败');return}
console.log(data.toString()) //成功
})
方法二:写两个回调
//参数传
ajax('get', '1.json', (data)=>{}, (error)=>{})
//或者对象传:
ajax('get', '1.json',{
success: ()=>{},
fail: ()=>{}
}
}
但是这两个方法有缺陷:
- 不规范,有人用success+error,有人用success+fail,有人用done+fail。
- 容易出现回调地狱,代码看不懂
- 很难进行错误处理
Promise
为了解决上述的三个问题,Promise出现了。
Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.
Promise创建方法
new Promise((resolve,reject) =>{
resolve(result) //任务成功则调用resolve(result)
reject(error) //任务失败则调用reject(error)
})
Promise使用方法
ajax = (method,url,options)=>{
return new Promise((resolve,reject)=>{
const {success,fail} = options //析构赋值,const sucess= options.success const fail = options.fail
const request = new XMLHttpRequest()
request.open(method,url)
request.onreadystatechange = ()=>{
if(request.readyState ===4){
if(request.status<400){
resolve.call(null,request.response)
}else {
reject.call(null,request)
}
}
}
request.send()
})
}
ajax('get','/xxx').then(
(response)=>{}, //成功回调函数,只传一个参数
(request)=>{} //失败回调函数,只传一个参数
)
Promise总结
- return new Promise((resolve,reject)=>{…})
- 任务成功调用resolve(result),任务失败调用reject(error)
- resolve和reject会再去调用成功和失败函数
- 使用.then(success,fail)传入成功和失败函数