什么是异步/同步
简单的来说,我们可以通过 是否能直接拿到结果 来判断是否为异步。
如果为同步,那么就必须等该代码执行完毕后在执行后面的代码。
如果为异步,那么就可以同时去执行其他代码。、
如何判断同步/异步
简单的来说,如果一个函数的返回值处于
- setTimeout
- AJAX(即XMLHttpRequest)
- addEventListener
那么,这个函数就是异步函数。
注意:ajax可以将其设置为同步,但如果设置为同步,会造成请求期间,整个页面卡住,因为同步操作必须等ajax请求完之后再执行后面的代码。
什么是回调
回调函数就是给别人调用的函数。
function f1(){}
function f2(fn){
fn()
}
f2(f1)
//这f1是一个回调函数,因为他是给f2调用的,而不是给我调用的
异步与回调的关系
异步与回调是合作关系,而非附属关系。
array.forEach( item => console.log(item) )
//例如,此时,回调就被用于同步操作了,所以,回调不一样要用于异步操作。
在执行异步操作时,我们可以给他一个回调函数,这样,当异步操作完成时,就能将其结果作为参数传给回调函数了。
异步与回调总结
function 摇色子(){
setTimeout(()=>{
return parseInt( Math.random() * 6) + 1
},1000)
return udnefined
}
上面就是一个异步操作,1s之后,才会得到结果。
function 摇色子(){
let result
setTimeout(()=>{
result = parseInt( Math.random() * 6) + 1
},1000)
return result
}
所以,正常情况下我们是无法得到result的。
此时,我们就需要一个回调函数了
function f1 (n){
console.log(n)
}
function 摇色子(fn){
setTimeout(()=>{
fn( parseInt( Math.random() * 6) + 1)
},1000)
return undefined
}
上面的代码中,f1只用到了一次,所以我们可以将其简化为一个匿名函数
function 摇色子(fn){
setTimeout(()=>{
fn( parseInt( Math.random() * 6) + 1)
},1000)
return undefined
}
摇色子(console.log)
Promise
上面,我们提到了,如果使用回调,我们就可以对异步操作的结果进行处理,但,如果异步任务有两个结果(例如成功/失败)呢?
我们可能会想到两个解决方法:
- 回调接受两个参数
- 使用两个回调
但上面两种方法有一些缺点:
- 不规范,名称五花八门(success+fail,success+error,done+fail)
- 容易出现回调地狱,使代码难以看懂
- 很难进行错误处理
所以,为了解决上面的问题,人们提出了Promise。
下面,使用AJAX的简单封装举例。
function ajax (menthod,url,options){
const {success,fail} = options
const request = new XMLHttpRequest()
request.open(menthod,url)
request.onreadystatechange = () =>{
if(request.readyState === 4){
if (request.status >= 200 &&
request.status < 300
){
success.call(null,request.response)
}else {
fail.call(null,request)
}
}
}
request.send()
}
ajax('GET','/xxx',{
success(response){},
fail : (request)=>{}
})
我们可以看到,上面的代码不够简洁,如果我们使用Promise
ajax = (method, url) => {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open(method, url);
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status < 400) {
resolve(request.response);
} else if (request.status >= 400) {
reject(request);
}
}
};
request.send();
});
};
ajax('GET','/xxx')
.then( (response)=>{} ,(request)=>{} )