异步与Promise

80 阅读3分钟

一、异步和同步

1、能直接拿到结果的是同步

  • 如,在医院挂号,拿到号才会离开

2、不能直接拿到结果的是异步

2.1、举例理解
  • 如,在餐厅门口等位,拿到号后可以去逛街。那什么时候能吃到饭?
  1. 可以每十分钟问一下前面还有几位(轮询)
  2. 微信扫码接收通知(回调)
2.2、以AJAX为例
  • request.send()并不能直接得到response
  • 须等到readyState为4,浏览器会回头调用request.onreadystatechange函数(类似于每隔几位微信就会发送等位提醒)
2.3、回调callback
  • 写给别人用的函数,就是回调
  • request.onreadystatechange就是我写给浏览器调用的(回头调用一下这个函数,“回头”也有“将来”的意思)
  • 举例
function f1(){}
function f2(fn){
  fn()
}
f2(f1) //f1传给f2(别人),f2调用了f1
//所以f1是回调
2.4、异步和回调
2.4.1、关系
  • 合作关系:异步任务需要在得到结果时通知JS来拿结果,一般用回调
  • 如何通知,参考2.2的AJAX例子
  1. 让JS留一个函数地址给浏览器,request.onreadystatechange
  2. 异步完成后,浏览器会回头调用该函数,即request.send()后readyState为4时
  3. 同时把结果作为参数传给该函数(readyState的状态码)
  • 这个函数是我写给浏览器调用的,所以是回调函数
2.4.2、区别
  • 异步一般用回调通知结果,但不是一定要用回调,也可以用轮询
  • 且回调函数也不一定只能用在异步任务里
  • 也可用在同步任务里,如array.forEach(n=>console.log(n)),同步回调

3、如何判断同步/异步

3.1、如果一个函数的返回值处于以下几种
  • setTimeout
  • AJAX(即XMLHttpRequest),需注意,千万不可把AJAX设置为同步
  • AddEventListener
  • 那么,就是异步任务
3.2、举例
3.2.1、摇骰子
function 摇骰子(){ //摇骰子()没有写return,其实是return undefined
  setTimeout(()=>{ //这个箭头函数有return,返回真正的结果1-6
    return parseInt(Math.random()*6)+1
  },1000)
}
//这是一个异步任务
3.2.2、摇骰子续
  • 如果此时,const n=摇骰子();console.log(n) //undefined,因为没有拿到结果
  • 如何拿到?用回调
function 摇骰子(fn){
  setTimeout(()=>{
    fn(parseInt(Math.random()*6)+1)
  },1000)
}

4、异步有成功/失败结果

4.1、方法一:回调接受两个参数
fs.readFile('/1.txt',(error,data)=>{
  if(error){console.log('失败');return}
  console.log(data.toString()) //成功
})
4.2、方法二:弄两个回调
ajax('get','/1.json',data=>{},error=>{}) //分别是成功回调和失败回调
ajax('get','/1.json',{
  success:()=>{},fail:()=>{} //接受一个对象,有两个key,表示成功和失败
})
4.3、以上方法一二都有问题
  • 不规范,名称可以五花八门,success+error、success+fail等
  • 很难进行错误处理
  • 容易出现回调地狱 微信图片_20230524212704.png(截图来自饥人谷课件)

二、Promise

1、简介

  • 1976年,Daniel P.Friedman和David wise提出Promise思想
  • 后人基于此发明了Future、Delay、Deferrde等
  • 前端结合Promise和JS制定了Promise/A+规范

2、以AJAX封装为例

微信图片_20230524171043.png(截图来自饥人谷课件)

3、改用Promise写法

  • return new Promise((resolve,reject)=>{...})
  • ajax()返回了一个含有.then()方法的对象 微信图片_20230524213615.png(截图来自饥人谷课件)

4、总结

  • 第一步
  1. return new Promise((resolve,reject)=>{...})
  2. 任务完成则调用resolve(result)
  3. 任务失败则调用reject(error)
  4. resolve和reject会再去调用成功和失败函数
  • 第二步 1.使用.then(success,fail)传入成功和失败函数