异步与同步
- 所谓异步就是不能立马拿到结果,需要一定的时间,例如去网红餐厅吃饭时排队事件。那这个结果要怎样才能拿到呢,可以通过轮询或回调拿到结果。
- 同步就是需要拿到结果后再再执行下一步,去医院挂号事件,就是只有当拿到号才会走,就称为同步。
回调
为了得到异步的结果最常用的方法是回调,虽然轮询也可以只是太傻了点。
- 回调就是写了不调用给别人用的函数就是回调
- 回调举例
function f1(){ }
function f2( ){
fn( )
}
f2(f1)
分析,f1并没有调用,但是把它传给了f2 ,并且f2调用了f1,所以f1是回调。 3. 异步任务需要通过回调函数来通知结果,但是回调函数不一定只可以用在异步任务里面,回调也可以用在同步任务里面,他们只是协作关系,并不绝对。
判断异步
如果一个函数的返回值处于setTimeout,ajax AddeventListener里面,那么这个函数就是异步函数。虽然ajax可以设置为同步的,但是谁要这样做就是个傻子,十分不推荐
function 摇骰子(){
setTimeout(()=>{ //箭头函数
return parseInt(Math.random() * 6) + 1
},1000)
// return undefined
}
分析由于摇骰子这个函数并没有写return,那就是return undefined
我们想要得到箭头函数里的结果,这就涉及到怎么拿到异步结果呢,可以使用回调。先写个函数,把函数地址给它function f1(x){ console.log(x) }
摇骰子(f1)然后等到得到结果后,把结果作为参数传给写的这个函数。
function 摇骰子(fn){
setTimeout(()=>{
fn(parseInt(Math.random()*6+1)
)},1000)
}
由于写的这个函数f1,只是调用了一次,所以我们可以简写,改为摇骰子(x=>{ console.log(x)}),也可以最后简写为摇骰子(console.log),不建议最后一种写法,如果参数不一致,可能出现问题。
异步任务的参数
如果异步任务有两个结果怎么办,两个办法
- 回调的时候接受两个参数吧
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: ()=>{}
})//接受一个对象,对象里面有两个key表示成功和失败
这些方法的不足,首先名称五花八门,有sucess+error,还有sucess+fail done+fail,其次出现地狱回调,代码让人看不懂,最后很难进行错误处理。为了解决这些缺陷,那么promise登场了
promise
以AJAX的封装为例来解释promise的用法
ajax = (method, url, options)=>{
const {success, fail} = options //析构赋值法 ,相当于 const success=options.success const fail=options.fail//
const request = new XMLHttpRequest()
request.open(method, url)
request.onreadystatechange = ()=>{
if(request.readyState === 4){
// c成功调用success,失败就调用fail
if(request.status < 400){
success.call(null, request.response)
}else if(request.status >= 400){
fail.call(null, request, request.status)
}
}
}
request.send()
}
ajax('get', '/xxx', {
success(response){}, fail: (request, status)=>{}
}) //左边是funtion缩写,右边是箭头函数 新语法。
修改成promise
首先,改一下调用的姿势
ajax('get', '/xxx', { success(response){}, fail: (request, status)=>{} })改为 ajax('get', '/xxx') .then((response)=>{}, (request, status)=>{})
源码为
ajax = (method, url, options)=>{
return new Promise((resolve, reject)=>{
const {success, fail} = options
const request = new XMLHttpRequest()
request.open(method, url)
request.onreadystatechange = ()=>{
if(request.readyState === 4){
//成功就调用resolve,失败就调用reject
resolve.call(null,request.response)
}else if(request.status >= 400){
reject.call(null, request)
}
}
}
request.send()
})
}
虽然封装的这个ajax函数十分的简陋,但是对于理解什么是promise已经足够了。 Promise构造函数接受一个函数作为参数,这个函数有两个参数,分别是reserve和Preject。resolve函数是在这个异步任务成功时调用,并且将成功结果作为参数传递出去,reject函数是异步任务失败的时候调用,它会将异步任务操作报告出的错误作为参数传递出去。
Promise.then()
Promise实例,会返回一个promise对象,它接受.then方法,接受两个回调函数作为参数,第一个回调函数表示任务成功时会调用,第二个函数表示任务失败的时候调用,这两个函数都接受promise对象传出的值作为参数。
Promise.all()
Promise.all的,用于多个promise实例,它会形成一个新的promise实例,只有当多个Promise实例都成功时,才会成功
例如Promise.all([promise1,promise2,promise3]).then(suceess,fail),只有当promise1,promise2,promise3都成功时sucess函数才会被调用。
Promise.race()
romise.race的,用于多个promise实例,同样会形成一个新的promise实例。 Promise.race([promise1, promise2]).then(success1, fail1)
promise1和promise2只要有一个成功就会调用success1;
promise1和promise2只要有一个失败就会调用fail1;
总之,谁第一个成功或失败,就认为是race的成功或失败