前置知识

一直以来,JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深入人心,近几年随着JavaScript开发模式的逐渐成熟,CommonJS规范顺势而生,其中就包括提出了Promise规范,Promise完全改变了js异步编程的写法,让异步编程变得十分的易于理解,同时Promise也已经纳入了ES6,而且高版本的chrome、firefox浏览器都已经原生实现了Promise,只不过和现如今流行的类Promise类库相比少些API

回调地狱callback

  1. doSomething(function(result) {
  2. doSomethingElse(result, function(newResult) {
  3. doThirdThing(newResult, function(finalResult) {
  4. console.log('Got the final result: ' + finalResult);
  5. }, failureCallback);
  6. }, failureCallback);
  7. }, failureCallback);

三个缺陷:

  1. 命名不规范,有人用success+error,有人用success+fail,有人用done+fail
  2. 代码可读性低,易出现回调地狱
  3. 很难捕获错误,进行错误处理

Promise

Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口
前端解决异步问题的统一方案

三个优势:

  1. 解决回调地狱,增强代码可读性
  2. 规范回调的名字或顺序
  3. 很方便地捕获错误

简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:

  1.   f1().then(f2);

Promise 对象:是由关键字 new 及其构造函数来创建的,该对象中传入表示成功和失败的函数,该函数的形参接收成功和失败两个函数

Promise使用

  1. resolve() 可以将异步数据传递出来,并将promise状态变为 fulfilled
  2. then() 可以拿到异步数据
  3. 同理,reject()和catch()也是如此
  1. //获取奶茶的方法
  2. function getTea(fn){
  3. setTimeout(()=>{
  4. fn('奶茶')
  5. },500)
  6. }
  7. //获取火锅的方法
  8. function getHotpot(fn){
  9. setTimeout(()=>{
  10. fn('火锅')
  11. },1000)
  12. }
  13. //调用获取火锅再获取奶茶的方法
  14. //默认按时间来讲应该是先获取到奶茶再获取火锅,但按指定顺序获取的话,需要在回调中嵌套回调
  15. getTea(function(data){
  16. console.log(data)
  17. getHotpot(function(data){ //多重嵌套容易出现回调地狱
  18. console.log(data)
  19. })
  20. })
  1. const getTea =()=>{
  2. return new Promise((resolve)=>{
  3. setTimeout(()=>{
  4. resolve('奶茶')
  5. },500)
  6. })
  7. }
  8. const getHotpot =()=>{
  9. return new Promise((resolve)=>{
  10. setTimeout(()=>{
  11. resolve('火锅')
  12. },1000)
  13. })
  14. }
  15. getTea().then(
  16. (data)=>{console.log(data)}
  17. return getHotpot()
  18. ).then(
  19. (data)=>{console.log(data)}
  20. )
  1. //async 的前提仍是基于 Promise
  2. const getTea =()=>{
  3. return new Promise((resolve)=>{
  4. setTimeout(()=>{
  5. resolve('奶茶')
  6. },500)
  7. })
  8. }
  9. const getHotpot =()=>{
  10. return new Promise((resolve)=>{
  11. setTimeout(()=>{
  12. resolve('火锅')
  13. },1000)
  14. })
  15. }
  16. //async 只是多封装一层async函数,然后调用这个async函数得到异步任务返回值
  17. async funtion getData(){
  18. let hotPot = await getHotpot() //await 代替 then 拿到resolve传递出来的一部数据
  19. console.log(hotPot)
  20. let tea = await getTea()
  21. console.log(tea)
  22. }
  23. //调用async 函数
  24. getData()

**return new Promose( (resolve, reject) => { } )**
该构造函数接受两个函数——resolvereject ——作为其参数。
当异步任务顺利完成且返回结果值时,会调用 resolve 函数;
而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
而resolve函数和reject函数则在.then()形参中声明了,即构成回调
resolve函数和reject函数都只接受一个参数

  1. const myFirstPromise = new Promise((resolve, reject) => {
  2. // ?做一些异步操作,最终会调用下面两者之一:
  3. //
  4. // resolve(someValue); // fulfilled
  5. // ?或
  6. // reject("failure reason"); // rejected
  7. });

AJAX的封装和调用为例子,来解释promise的用法:

纯AJAX封装和AJAX调用:
image.png

AJAX+Promise 示例:
AJAX源码封装上新增Promise对象:
return new Promose( (resolve, reject) => { } )
如何得到ajax()返回的对象?
在ajax封装源码的时候,在ajax函数的开头直接返回Promise构造函数的对象,该对象中传入表示成功和失败的函数,该函数的形参接收成功resolve和失败reject两个函数(固定函数命名),而这两个函数又会各自去调用尔后声明了的then的第一个实参或第二个实参
image.png

AJAX调用上采用链式:

调用的时候传“预案”
ajax()返回了一个含有.then()方法的对象,以便进行链式操作
then方法的传入两个参数函数,第一个参数是成功函数,第二个参数是失败函数,即两个回调函数
两个回调函数只能接收一个形参
image.png

image.png

Axios库

目前最新的AJAX库,抄袭jQuery的封装思路

代码示例:

  1. axios.get('/5.json')
  2. .then(response => console.log(response)
  3. )