上节课我们介绍了Promise是什么以及为什么我们要使用Promise,而且通过案例来介绍了Promise的基本使用方法以及工作流程,那么这节课我们来做一下Promise的实践练习。

fs文件操作

大家可能有些人知道fs的用途是什么,这是一个可以从计算机硬盘读取文件的一个模块,我们现在有一个需求,要求我们来读取当前目录下的resource目录中的content.txt文件。那么我们怎么处理?

纯回调函数实现

const fs = require("fs");

fs.readFile("./resource/content.txt", (err, data) => {
  if (err) throw err;
  console.log(data);
});

首先我们用纯回调函数来实现一下,我们先是导入了fs库,然后调用readFile方法来读取文件,这个方法接收两个参数,第一个是文件路径,第二个是一个回调函数,这个回调函数中也接收两个参数,一个是异常,一个是读取到的文件内容。我们来看回调函数体,如果有异常出现,就抛出异常,否则就打印文件内容。我们来执行一下这段代码。

image-20220307162349453

我们来看一下,代码执行成功了,打印出了一串buffer,这是看不见文件内部的实际内容的。那么我们在data后面加一个toString()专成字符串输出再看一下

image-20220307162556747

这次我们看见我们打印出来的文件内容中就写了test file这两个单词。

Promise方式实现

那么我们如果用Promise来封装这个操作应该怎么写呢?我们来看代码:

const fs = require("fs");

let p = new Promise((resolve, reject) => {
  fs.readFile("./resource/contentt.txt", (err, data) => {
    if (err) {
      reject(err);
    } else {
      resolve(data);
    }
  });
});

p.then(
  value => console.log(value.toString()),
  reason => console.log(reason)
);

我们来看,第一步,我们先来实例化一个Promise对象,接收一个函数作为参数,函数接收两个参数,resolvereject函数,然后函数体中包裹一个异步操作,就是我们的文件读取操作。然后还是像之前一样的判断,如果有异常,这次我们就不直接抛出异常了,我们调用reject函数,代表着异步任务失败,并且把err对象传给reject函数。如果没有异常,那就说明异步任务成功了,调用resolve函数,并且将data传给resolve函数。

接下来我们就可以调用Promise对象的then方法了,then方法接收两个函数,第一个函数为Promise对象状态为成功时调用,并且接收到异步任务成功时的结果值,然后我们打印出来。第二个函数为Promise对象状态为失败时调用,也会接收到异步任务失败时的结果值,并且打印出来。

那么我们来看一下结果。大家如果看得仔细一点的话就会发现,上面那段代码我故意把文件路径写错了。我们来看一下执行结果:

image-20220307164530849

我们先是正确的时候执行了一次,我们看见控制台中成功打印出了文件中的内容,然后我们把文件路径写错再执行一次,这次打印出了我们的错误对象。

以上就是fs读取文件的两种实现形式的练习。

Ajax请求

前面我们做了一个读取文件的练习,那么接下来我们来做一个发送ajax请求的练习,我们现在有这么一个需求:

image-20220307165829088

我们现在这个页面上面有一个按钮,当我们点击按钮之后就会发送一个ajax请求,并且把请求结果打印在控制台中。

Ajax方式

那么我们怎么处理?如果直接用ajax不用Promise的话就是ajax的固定流程:

<body>
  <div class="container">
    <h2 class="page-header">Promise AJAX</h2>
    <button id="btn" class="btn btn-primary">Click to send ajax</button>
  </div>
  <script>
    const btn = document.getElementById("btn");
    btn.addEventListener(
      "click",
      () => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", "https://api.apiopen.top/getJoke");
        xhr.send();
        xhr.onreadystatechange = () => {
          if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
              console.log(xhr.response);
            } else {
              console.log(xhr.status);
            }
          }
        };
      });
  </script>
</body>

我们先定位到按钮元素,然后绑定点击事件,在点击事件中,我们首先实例化一个xhr对象,然后设置我们发送的请求方式和请求URL,然后发送请求,接下来我们要处理响应结果。判断readyState是不是为4,如果为4,再判断请求状态码是不是为2xx,因为状态码只要是2开头的,都代表请求成功了。所以说我们并不是只判断200,如果为2xx那么答应响应体,否则打印状态码。那么我们来看一下实际效果:

image-20220307170656703

我们看见了控制台中打印出了很多接口返回的数据。这就是我们完全使用ajax来发送请求。

Promise方式

那么上面的这一部分如何使用Promise的方式来实现呢?

btn.addEventListener(
  "click",
  () => {
    let p = new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", "https://api.apiopen.top/getJoke");
      xhr.send();
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve(xhr.response);
          } else {
            reject(xhr.status);
          }
        }
      }
    });
    p.then(
      value => console.log(value),
      reason => console.log(reason)
    );
  });

我们来看代码,首先实例化一个Promise对象,并传入一个函数,该函数接收两个函数作为参数,这个函数的函数体包裹一个异步操作,那么就是说ajax请求的部分都封装在这个函数体中,然后依然还是判断状态码,如果状态码是2xx那么执行resolve函数,并把响应体传给resolve函数,否则说明请求失败,调用reject函数并把状态码传给reject函数,接下来我们调用then方法,在then方法中定义两个函数,分别接收成功与失败时的结果值并打印到控制台中。

那么我们这么写的效果是什么样子呢?我们来看一下:

image-20220307172019312

首先我们故意将url的路径写错,然后接口报了404,控制台中也成功打印了404,那么接下来我们把url路径修改成正确的路径再来请求看一下:

image-20220307172158871

这一次成功打印了很多接口返回的信息。

以上便是Promiseajax请求的一个封装,大家看是不是就那么一个固定的路数?只要把我们的异步操作放到Promise对象里,操作失败就调reject函数,成功就调resolve函数,然后再调用Promise对象的then方法,在then方法中定义两个函数,成功了执行第一个函数,否则执行第二个函数

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/use_promise_test/