理解ES6中Promise,并用 Promise 封装一个 Ajax 请求(含express服务器创建和设置跨域)

1. 从基本理解开始

首先,Promise 是一个构造函数,可以用来 new 一个实例。

以前的异步编程当中,经常会出现地狱回调问题,也就是函数中嵌套很多层函数,而 Promise 就用于解决这个问题,使得代码看起来简洁很多。但是呢,它的代码看起来简洁,前提是要你懂得它的代码执行过程,你不懂它的执行过程,多简洁也白费,还不如层层嵌套的流程性看得容易明白一点。

下面用实例说明使用 Promise 实现异步编程中的代码执行过程。

1.1 先看看这个异步编程

setTimeout(()=>{
   console.log('成功');
},1000)
// 1s之后打印 成功
// 可是,这个过程一定会成功吗?也就是最终一定会打印出 成功 吗,不成功怎么办?

1.2 接着上面的例子,我们用 Promise 来看看

// 先 new 一个 Promise 实例
// new 实例的时候,传入一个函数
// 传进来的函数可以传进两个参数,名字可自定义,推荐分别为 resolve 和 reject
// 两个参数中,第一个是异步操作中成功后回调的方法,第二个是失败后回调的方法,当然他们是可以省略的
let p = new Promise(function (resolve, reject) {
  setTimeout(() => {
    // 我们不像之前那样直接打印了,而是将“成功”或“失败”当参数传给这两个方法
    // 成功就实行 resolve('成功!'),失败就执行 reject('失败!'),二选一
    resolve('成功!')
    reject('失败!')
  }, 1000)
})

// 执行完上面的代码后,其实什么也没打印出
// 接着到下面代码了,p 实例有个 then 的方法
// then 中又可以传进两个方法
// 第一个方法是上面执行了 resolve('成功!') 后执行的
// 第二个方法是上面执行了 reject('失败!') 后执行的
p.then(
  function (value) {  // 形参 value,它传进来的实参是  '成功!'
    console.log(value)
  },
  function (reason) {  // 形参 reason,它传进来的实参是  '失败!'
    console.log(reason)
  }
)

2. 用Promise封装Ajax请求

2.1 创建一个Express服务器,开启CROS跨域资源共享

// 1. 引入epress,记得先安装此模块
import epress from 'express'

// 2. 执行epress(),用 app 接收
const app = epress()

//3. 设置跨域访问(设置在所有的请求前面即可)
app.all('*', function (req, res, next) {
  //3.1 设置允许跨域的域名,*代表允许任意域名跨域
  res.header('Access-Control-Allow-Origin', '*')
  //3.2 允许的header类型
  res.header('Access-Control-Allow-Headers', 'content-type')
  //3.3 跨域允许的请求方式
  res.header('Access-Control-Allow-Methods', 'DELETE,PUT,POST,GET,OPTIONS')
  if (req.method == 'OPTIONS') res.sendStatus(200) //让options尝试请求快速结束
  else next()
})

// 5. 挂在路由
app.get('/user', (req, res) => {
  res.send({
    data: {
      name: 'hong',
      sex: '男',
      age: 20
    }
  })
})

// 4. 开启服务器
app.listen(80, () => {
  console.log('server runing at http://127.0.0.1')
})

2.2 发起Ajax请求

(1)先使用常规的方式

 执行过程说明:

  1. 请求成功了,执行打印 xhr.response 这个返回结果。
  2. 请求失败了,执行打印 请求失败!+ xhr.status
  3. 这样有 if else 嵌套问题
// 1. new 实例
var xhr = new XMLHttpRequest()
// 2. 初始化
xhr.open('get', 'http://127.0.0.1/user')
// 3. 发送
xhr.send()
// 4. 绑定事件,处理结果
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      // 4.1 处理请求成功后服务器返回是数据,这里只做简单的打印处理吧
      console.log(xhr.response)
    } else {
      // 4.2 处理请求失败的情况
      console.error('请求失败!' + xhr.status)
    }
  }
}

/* 4. 步骤4的另外一种实现方式
      进入onload之后,只出现了状态码4。
      也就是说,只有处于状态码4,请求已完成,响应已就绪的情况下,才会进入onload。
      只要进入onload请求中,一定是已经到4这个状态了。

xhr.onload = function () {
  if (xhr.status === 200) {
    // 4.1 处理请求成功后服务器返回是数据,这里只做简单的打印处理吧
    console.log(xhr.response)
  } else {
    // 4.2 处理请求失败的情况
    console.error('请求失败' + xhr.status)
  }
}
*/

(2)再使用Promise封装Ajax的方式

// 1. 创建 Promise 实例
let p = new Promise(function (resolve, reject) {
  var xhr = new XMLHttpRequest()
  xhr.open('get', 'http://127.0.0.1/user')
  xhr.send()
  xhr.onload = function () {
    // 请求成功,执行resolve,并将返回的数据作为参数传入
    resolve(xhr.response)
    // 请求失败
    reject('请求失败' + xhr.status)
  }
})

// 2. 处理成功和失败的回调
p.then(
  // 成功,res 得到的就是返回的数据
  function (res) {
    console.log(res)
  },
  // 失败,reason 得到的就是失败的返回原因
  function (resaon) {
    console.log(reason)
  }
)

 3. 总结

Promise 实现异步编程过程中,代码整洁了,不用层层嵌套,也就是解决了地狱回调问题。

 

posted @ 2022-05-09 20:35  RHCHIK  阅读(561)  评论(0编辑  收藏  举报