Promise

Promise是什么

promise是ES6的一门新技术,是JS中处理异步编程解决方法,旧的方法是单纯地使用回调函数

异步编程

步编程是一种使用非阻塞性函数或者非顺序执行逻辑的编程方式,通过使用异步编程,可以避免因为等待慢操作(如读写文件、访问数据库或网络请求)而浪费CPU的时间,提高程序执行效率。

在同步编程中,代码会按照从上到下的顺序依次执行,每一行代码都必须等待上一行代码执行完毕之后才能执行。这种顺序执行的方式很容易理解,也很容易编写代码,但是有个明显的缺点:无法充分利用计算机资源,当遇到需要大量时间的操作时(如I/O操作),CPU就会处于空闲状态。

而异步编程则可以解决这个问题。在异步编程中,函数的调用不会阻塞后续操作的执行。当异步操作(如I/O操作)被调用后,程序不会等待其结果,而是立即执行后续的代码。当异步操作完成后,通过事件或者回调函数来处理结果。

常见的异步编程

  • fs文件操作:
    通过 fs 模块的函数例如 fs.readFile 或 fs.writeFile 读写文件都是异步操作。

    require('fs').readFile('./imdex.html', (err,data)=>{回调函数})
    
  • 数据库操作:例如查询数据库,这种 I/O 操作通常都是异步的。

  • AJAX请求:使用 fetch API 或者 XMLHttpRequest 发送的 HTTP 请求,他们不会阻塞后续代码的执行

    $.get('/server', (data)=>{回调函数})
    
  • 定时操作:setTimeout 和 setInterval

    setTimeOut(()=>{回调函数}, 2000)
    
  • 用户操作:如按钮点击、键盘输入等用户接口事件,对这些事件的响应处理也是异步操作。

  • Promise
    任何返回 Promise 的函数或方法都是异步的。

    const p = new Promise((reslove, reject) => {
    	reslove()
        }).then(
          () => {
            // 成功回调
            alert("恭喜,中奖啦");
          },
          () => {
            // 失败回调
            alert("再接再厉");
          }
        );
    

    从语法上来说: Promise是一个构造函数,是一种异步编程的方式
    从功能上来说: promise对象用来封装一个异步操作并可以获取其成功/失败的结果值,可以处理异步编程的返回结果

    • Web Workers:多线程机制也是一种异步操作。 Web Workers 是一种让 Web 内容在后台线程运行脚本的方法。
    • WebSockets 和 Server-Sent Events:这两种技术都用于服务器和客户端之间的双向通信,事件驱动的处理方式也是异步的。

常规逻辑下,异步编程执行完之后我们需要根据异步编程的结果处理一些内容,称之为处理异步编程的解决方法,常见的处理方法有回调函数,还有Promise

Promise的优势

  • 支持链式调用,解决回调地狱问题。
    回调地狱:多个函数嵌套调用以达到函数异步调用的效果
    在这里插入图片描述
    通过嵌套调用,函数1执行后才能执行函数2,函数2执行后才能执行函数3…
    这样肃然达到了异步调用的效果,却引来一个问题:函数嵌套的层级太深,代码不断向前缩进,不便于阅读,不便于异常处理。

  • Promise指定回调函数的方式更加灵活
    旧的:必须在启动异步任务前指定回调函数
    Promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(可以有多个, .then方法)

Promise使用案例

抽奖案例

案例:抽奖案例,点击按钮进行抽奖,将抽检结果进行弹窗显示。

  • 普通实现:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <div class="container">
          <h2 class="page-header">Promise初体验</h2>
          <button id="btn" class="btn">点击抽奖</button>
        </div>
        <script>
          // 随机数
          function rand(m, n) {
            return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
          }
          const btn = document.querySelector("#btn");
          btn.addEventListener("click", () => {
            // setTimeout实现
            setTimeout(() => {
              // 30%中奖概率
              const n = rand(1, 100);
              console.log("n", n);
              if (n <= 30) {
                alert("恭喜,中奖啦");
              } else {
                alert("再接再厉");
              }
            }, 1000);
          });
        </script>
      </body>
    </html>
    
    
  • Promise实现:
    (Promise是一个构造函数,实例化的参数是两个函数reslove和reject,reslove是成功时调用的函数,reject是失败时调用的函数,实例化函数里面存放异步任务
    (实例化后的Promise有.then方法,该方法有两个参数,第一个是Promise调用reslove后执行的结果,第二个是Promise调用reject后执行的结果 )
    (如果在调用reslove和reject时进行了参数传递,他们的参数分别会传递个.then函数的第一个回调函数和第二个回调函数)

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <div class="container">
          <h2 class="page-header">Promise初体验</h2>
          <button id="btn" class="btn">点击抽奖</button>
        </div>
        <script>
          // 随机数
          function rand(m, n) {
            return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
          }
          const btn = document.querySelector("#btn");
          btn.addEventListener("click", () => {
            // promise实现
            /*
                reslove, reject都是函数参数
                当异步任务成功掉reslove,失败掉reject
             */
            const p = new Promise((reslove, reject) => {
              //包裹异步操作,对异步任务进行封装
              setTimeout(() => {
                // 30%中奖概率
                const n = rand(1, 100);
                if (n <= 30) {
                  // 将Promise的状态设置为成功
                  reslove();
                } else {
                  // 将Promise的状态设置为失败
                  reject();
                }
              }, 1000);
            }).then(
              () => {
                // 成功回调
                alert("恭喜,中奖啦");
              },
              () => {
                // 失败回调
                alert("再接再厉");
              }
            );
          });
        </script>
      </body>
    </html>
    

fs案例

使用Promise读取文件操作

const fs = require('fs')

// 回调函数形式
fs.readFile('./public/content.txt',(err,data)=>{
    if(err){
        throw(err)
    }else{
        // 直接读取data是一个Buffer格式的数据,<Buffer 48 65 6c 6c 6f ef bc 8c e6 88 91 e6 98 af 63 6f 6e
        console.log('context文件内容:', data);
        // 使用toString方法可以转变成可读文件
        console.log('context文件内容:', data.toString());
    }
})

// Promise形式
let p = new Promise((reslove, reject)=>{
    fs.readFile('./public/content.txt',(err,data)=>{
        if(err){
            reject(err)
        }else{
            reslove(data)
        }
    })
}).then((value)=>{
    // 使用toString方法可以转变成可读文件
    console.log('context文件内容:', value.toString());
},(reason)=>{
    console.log(reason);
})

ajax案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <h2 class="page-header">Promise 封装 Ajax</h2>
      <button id="btn" class="btn">点击发送AJAX</button>
    </div>
    <script>
      const btn = document.querySelector("#btn");
      //   AJAX实现
      btn.addEventListener("click", () => {
        // 创建对象
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open("GET", "https://api.apiopen.top/getJoke");
        // 发送
        xhr.send();
        // 处理响应结果
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
              // 控制台输出响应体
              console.log("成功", xhr.status, xhr.response);
            } else {
              // 控制台输出响应状态码
              console.log("失败", xhr.status);
            }
          }
        };
      });

      //   Promise实现
      btn.addEventListener("click", () => {
        new Promise((reslove, reject) => {
          // 创建对象
          const xhr = new XMLHttpRequest();
          // 初始化
          xhr.open("GET", "https://api.apiopen.top/getJoke");
          // 发送
          xhr.send();
          // 处理响应结果
          xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
              if (xhr.status >= 200 && xhr.status < 300) {
                reslove(xhr.response);
              } else {
                reject(xhr.status);
              }
            }
          };
        }).then(
          (value) => {
            console.log("成功", value);
          },
          (reason) => {
            console.log("失败", reason);
          }
        );
      });
    </script>
  </body>
</html>

Promise封装,fs封装

封装一个函数mineReadFile读取文件内容。

const { resolve } = require('path')

function mineReadFile(path) {
    return new Promise((resolve, reject) => {
        // 读取文件
        require('fs').readFile(path, (err, data) => {
            if (err) reject()
            resolve(data)
        })
    })
}

mineReadFile('./resource/content.txt').then((value) => {
    console.log("文件内容是", value.toString());
}, (reason) => {
    console.log(reason);
})

Promise封装,ajax封装

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      /*
           封装一个函数sendAjax发送GET AJAX请求
           参数 URL,请求地址
           返回结果 Promise对象
       */
      function sendAjax(url) {
        return new Promise((resolve, reject) => {
          const xhr = new XMLHttpRequest();
          xhr.responseType = "json";
          xhr.open("GET", url);
          xhr.send();
          // 处理结果
          xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
              // 判断成功
              if (xhr.status >= 200 && xhr.status < 300) {
                resolve(xhr.response);
              } else {
                reject(zhr.status);
              }
            }
          };
        });
      }

      sendAjax("https://api.apiopen.top/getJoke").then(
        (value) => {
          console.log("结果", value);
        },
        (reason) => {
          console.log(reason);
        }
      );
    </script>
  </body>
</html>

上述案例就是对ajax的Promise封装,封装后的函数只需要输入请求地址,请求结果使用 .then进行接收。我们常用的axios发送ajax请求,就是对ajax的Promise封装。

util.promisify方法

util.promisify 方法:

  • 接受一个参数是一个函数,且该函数满足:最后一个参数是错误优先的回调函数, 即(err,value)=>{}格式
  • 返回结果是一个promise对象
/**
 * util.promisify 方法:
 * 接受一个参数是函数, 且该最后一个参数是(err,value)=>{}格式的函数
 * 返回结果是一个promise对象
 */
 // require('fs').readFile(path, (err, value)=>{})
let mineReadFile = require('util').promisify(require('fs').readFile)

mineReadFile('./resource/content.txt').then(value => {
    console.log('文件内容是:', value.toString());
})

util.promisify最常用的情形: 将普通的回调函数形式的异步编程 封装成 Promise形式的异步编程.
其实util.promisify的原理就是对回调函输进行Promise封装,类似于上述按案例 Promise封装,fs封装.

Promise的状态

Promise的状态是什么

Promise状态是Promise实例对象身上的一个属性PromiseState.

输出一个Promise对象如下:

[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: null

Promise的三种状态

属性PromiseState的取值有三种:

  • pending 未决定的 (初始状态)
  • resolved / fullfilled 成功
  • rejected 失败
    PromiseState的值是内置的我们不能直接进行操作。

Promise的状态改变

promise的状态改变只可能有两种情况

  • pending变为resolved
  • pending变为rejected

有且只有这两种情况,且一个Promise对象的状态只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason。

Promise的结果

Promise的结果是什么

Promise结果是Promise实例对象身上的另一个属性PromiseResult,保存的是Promise对象成功或失败的结果。
输出一个Promise对象如下:

[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: null

Promise的结果的设置

Promise的结果的设置是通过Promise的 resolve(value)reject(value)两个函数的参数设置的,他们传递的是什么参数 Promise的结果值(PromiseResult)就是什么。

Promise的API

Promise的构造函数

Promise对象的创建是通过Promise的构造函数创建的。new Promise((resolve, reject)=>{})
(resolve, reject)=>{}也叫做执行器函数,resolve和reject是两个函数:resolve函数是成功调用的函数;reject函数是失败调用的函数。

重要:执行器(resolve, reject)=>{}中的代码是同步的,不是异步的,所谓同步是指(resolve, reject)=>{}中代码的执行时机和Promise外的代码是同步执行的。

console.log(1);
new Promise((resolve, reject) => {
  // 这里的代码是同步调用的
  console.log(2);
});
console.log(3);

输出结果: 123

Promise.prototype.then方法

就是Promise的.then方法,他是Promise原型上的一个方法:.then((onResolved, onReject) =>{})

  • onResolved函数:成功时调用的回调函数,Promise中使用resolve方法对应的函数。
  • onReject函数:失败时调用的回调函数,Promise中使用reject方法对应的函数。
    重要:.then方法的返回值仍然是一个Promise对象,可以接着调用.then方法,这就是我们所说的链式调用

Promise.prototype.catch方法

指定的是Promise的失败的回调,.catch((onReject)=>{}),Promise中使用reject方法时就会调用catch中的回调。
eg:

	new Promise((resolve, reject) => {
	  reject("error");
	}).catch((error) => {
	  console.log(error);
	});

Promise.reslove方法

注意该方法是Promise函数对象上的方法,不是实例对象身上的方法,上面说的.then和.catch方法是实例对象身上的方法。
Promise.reslove((value)=>{}) :
value是成功的数据或Promise对象,并且该函数返回的是一个成功/失败Promise对象
eg:

      console.log(Promise.resolve(521));

输出:在这里插入图片描述
传递的value参数和返回结果的关系:

  • 如果传入的参数为非Promise类型的对象,则返回的结果为成功promise对象
  • 如果传入的参数为 Promise对象,则参数的结果决定了返回的结果。如果参数是成功的Promise对象,那么结果就是成功的Promise对象;如果参数是失败的Promise对象,那么结果就是失败的Promise对象。

注意 :和Promise执行器中的reslove方法不一样,Promise执行器中的reslove方法返回值是undefine

new Promise((resolve, reject) => {
   console.log(resolve("success"));
 }).catch((error) => {
   console.log(error);
 });

输出:在这里插入图片描述

Promise.reject方法

注意该方法是Promise函数对象上的方法。
Promise.reject((reason)=>{}) :
reason是失败的原因,并且该函数返回的是一个失败的Promise对象。失败的结果是传入的值。

eg:

console.log(Promise.reject(521));
console.log(
   Promise.reject(
     new Promise((resolve, reject) => {
       resolve("success");
     })
   )
 );

在这里插入图片描述

Promise.all方法

Promise.all((promiseArray)=>{}),promiseArray表示的是多个Promise对象,Promise组成的数组。
Promise.all返回的是一个新的promise:只有所有的promise都成功返回的Promise对象的状态才是成功,值是成功的promise的结果组成的数组;只要有一个失败了返回的Promise对象的状态就是失败,值是第一个失败的promise的结果。

注意: promiseArray中的内容是一起执行的不是顺次执行的。

eg:

let p1 = new Promise((resolve, reject) => {
  resolve("ok");
});
let p2 = Promise.resolve("Success");
let p3 = Promise.resolve("on Yeah");

const result = Promise.all([p1, p2, p3]);

console.log(result);

结果:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      let p1 = new Promise((resolve, reject) => {
        resolve("ok");
      });
      let p2 = Promise.reject("Error");
      let p3 = Promise.reject("on Yeah");

      const result = Promise.all([p1, p2, p3]);

      console.log(result);
    </script>
  </body>
</html>

结果:
在这里插入图片描述

实战:使用Promise.all

Promise.all使用

const deleteFunList:Array<()=>void> = []
// 异步函数
const deleteFun = (region) => {
  return () => {
    // 一定将axios请求进行返回
    return axiosApi.deleteConfig({
      id: detailValue.value && detailValue.value.id,
      region
    })
  }
}
const originRegionList=['ar','cn','am','ai']
originRegionList.forEach(item => {
  if (nowRegionList.indexOf(item) === -1) {
    deleteFunList.push(deleteFun(item))
  }
})

await Promise.all(deleteFunList.map(item => item()))

axios请求

deleteConfig(data) {
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        await axios({
          url: API.deleteConfig,
          method: 'post',
          data
        }).then(res => res.data)
          .then(data => {
            resolve(data)
          }).catch(error => {
            reject(error)
          })
      }, 3000)
    })
  }

需要注意的点:

  • deleteFun 返回的箭头函数仍然需要有返回值,返回之后Promise.all才能接收到参数
  • axios模拟延迟请求的时候不能只用setTimeout还需要使用new Promise包裹:
return new Promise((resolve, reject) => {
      setTimeout(async () => {
        await axios({})
        })
       }

Promise.race方法

Promise.race((promiseArray)=>{}),promiseArray表示的是多个Promise对象,Promise组成的数组。
Promise.all返回的是一个新的promise:promiseArray中第一个完成的Promise的结果状态就是返回的promise的状态。

eg:

let p1 = new Promise((resolve, reject) => {
		resolve("ok");
	});
let p2 = Promise.reject("Success");
let p3 = Promise.resolve("on Yeah");

const result = Promise.race([p1, p2, p3]);

P1执行最快:
在这里插入图片描述

Promise几个关键问题

如何改变Promise的状态

  1. 调用resolve函数,调用Promise函数将状态从Pending转换成fulfilled
  2. 调用reject函数,调用Promise函数将状态从Pending转换成rejected
  3. 抛出错误,调用throw,调用Promise函数将状态从Pending转换成rejected

Promise指定多个成功和失败的回调函数(链式调用.then),是否都会调用

当Promise改变为对应状态时都会调用,链式调用。

改变Promise的状态和指定回调函数谁先谁后

都有可能:

  • 正常情况下是先指定回调函数(回调函数指的是.then中的回调函数,指定回调函数的意思是进行回调函数的加载)再修改状态。
  • 但是也可能先改变状态再指定回调函数。

(1) 先指定回调函数再修改状态

  • Promise中的函数时异步任务
let p = new Promise((reslove, reject) => {
  setTimeout(() => {
    reslove("OK");
  }, 1000);
});
p.then(
  (value) => {
    console.log(value);
  },
  (reason) => {
    console.log(reason);
  }
);

(2) 先改变状态再指定回调函数

  • 在执行器中直接调用 reslove/ reject 函数
let p = new Promise((reslove, reject) => {
  reslove("OK");
});
p.then(
  (value) => {
    console.log(value);
  },
  (reason) => {
    console.log(reason);
  }
);
  • 延迟.then()方法的执行
let p = new Promise((reslove, reject) => {
  setTimeout(() => {
    reslove("OK");
  }, 1000);
});
setTimeout(() => {
  p.then(
    (value) => {
      console.log(value);
    },
    (reason) => {
      console.log(reason);
    }
  );
}, 2000);

then回调函数什么时候执行

Promise的状态发生变化后就会调用then回调函数,Promise执行器函数中既可以是同步函数也可以是异步函数,then回调函数在Promise执行器中的函数执行完之后再执行。

then方法返回结果的特点

.then方法的返回结果是一个Promise对象,后面可以继续调用.then方法。
.then方法的返回的Promise对象的状态由then()方法指定的回调函数的返回结果决定:

  • 如果抛出异常(throw),.then方法的返回的Promise对象的状态是reject, 值为throw抛出的内容
  • 如果返回的是非promise的任意值,.then方法的返回的Promise对象的状态为resolved, 值为返回的内容
  • 如果返回的是另一个新promise,此promise的结果就会成为.then方法的返回的Promise对象的结果
  • 注意: 如果没有返回结果,默认返回结果就是 undefined,undefined不是Promise对象,所以返回结果就是状态为resolved, 值为undefined的Promise对象
let p = new Promise((resolve, reject) => {
  resolve("ok");
});
let result = p.then(
  (value) => {
    //   console.log(value);
    // 1. 抛出错误
    //   throw "出错了";
    // 2. 返回结果是非Promise类型的对象
    //   return 521;
    // 3. 返回的是Promise对象
    return new Promise((resolve, reject) => {
      reject("error");
    });
  },
  (reason) => {
    console.err(reason);
  }
);

console.log("result", result);

返回结果:

  1. 抛出错误
    在这里插入图片描述
  2. 返回结果是非Promise对象
    在这里插入图片描述
  3. 返回结果是Promise对象
    在这里插入图片描述

Promise如何串联多个操作任务

(1) promise 的 then()返回一个新的promise,可以开成then()的链式调用
(2) 通过then 的链式调用串连多个同步/异步任务
eg:

new Promise((resolve, reject) => {
  // 异步任务1
   setTimeout(() => {
     resolve("OK");
   }, 1000);
 })
   .then((value) => {
     // 异步任务2
     return Promise((resolve, reject) => {
       resolve("success");
     });
   })
   .then((value) => {
     console.log(value);
   });

隔1s后返回:
在这里插入图片描述

Promise的异常穿透

Promise的异常穿透是指可以在链式调用的最后指定失败的回调(.then的第二个参数或者catch方法)。
最后的失败回调函数可以捕获该链式调用中的所有失败情况。
eg:

new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("error");
  }, 1000);
})
  .then((value) => {
    console.log(111);
  })
  .then((value) => {
    console.log(222);
  })
  .then((value) => {
    console.log(333);
  })
  .catch((reason) => {
    console.warn(reason);
  });

输出:
在这里插入图片描述

中断Promise链

Promise链指的是Promise的链式调用,有且仅有一种方法可以中断Promise的链式调用:返回pending状态的Promise对象(eg:return new Promise(()=>{}))。

原理:返回pending状态的Promise,就是Promise的状态没有改变,状态没有改变,就不会继续向下执行。

new Promise((resolve, reject) => {
setTimeout(() => {
  reject("error");
}, 1000);
})
.then((value) => {
  console.log(111);
  return new Promise(()=>{})
})
.then((value) => {
  console.log(222);
})
.then((value) => {
  console.log(333);
})
.catch((reason) => {
  console.warn(reason);
});

输出:
在这里插入图片描述

自定义(手写)Promise

  1. 基本结构
  • 构造函数有一个参数
  • 有.then方法,在原型上需要添加.then方法,并且有两个参数
  1. 实现:
    Promise.js
class Promise{
    // 构造方法
    constructor(executor) {
        // 属性
        this.PromiseState = 'pending'
        this.PromiseResult = null
        // 存储then
        this.callback = []
        const self = this

        // resolve函数 
        function resolve(data) {
            // 判断,确保状态只能被修改一次
            if (self.PromiseState !== 'pending') return;
            // 修改对象的状态(PromiseState)
            // 直接使用this.PromiseState,this指向的是windowa,而不是实例对象 
            self.PromiseState = 'fulfilled'
            // 修改对象的结果(PromiseResult)
            self.PromiseResult = data
            // 调用then方法
            setTimeout(() => {
                self.callback.forEach((item) => {
                    if (item.onResolved) {
                        item.onResolved(data)
                    }
                })
            })

        }  
        // reject函数
        function reject(data) {
            // 判断,确保状态只能被修改一次 
            if (self.PromiseState !== 'pending') return;
            // 修改对象的状态(PromiseState)
            self.PromiseState = 'reject'
            // 修改对象的结果(PromiseResult)
            self.PromiseResult = data
            // 调用then方法
            setTimeout(() => {
                self.callback.forEach((item) => {
                    if (item.onReject) {
                        item.onReject(data)
                    }
                })
            })
        }

        // 捕获异常(throw抛出的错误)
        try {
            // 同步调用的 执行器函数
            executor(resolve, reject)
        } catch (e) {
            // 修改状态为失败
            reject(e)
        }
    }

    // then方法
    // 添加then方法
    then(onResolved, onReject) {
        const self = this
        // 处理回调函数的参数
        if (typeof onResolved !== 'function') {
            onResolved = value => value
        }
        if (typeof onReject !== 'function') {
            onReject = reason => {
                throw reason
            }
        }
        // 返回Promise状态的对象
        return new Promise((resolve, reject) => {
            // 结果处理函数
            function resultCallback(typeFunction) {
                try {
                    // 获取回调函数的执行结果
                    let result = typeFunction(self.PromiseState)
                    if (result instanceof Promise) {
                        // 如果是Promise对象的话,直接返回Promise
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    } else {
                        // 不是Promise对象的话,结果的对象状态为成功
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }
            // 成功的回调(then方法是Promise实例对象调用的,所以this指向的是实例对象)
            if (this.PromiseState === "fulfilled") {
                setTimeout(() => {
                    resultCallback(onResolved)
                })
            }
            // 失败的回调
            if (this.PromiseState === "rejected") {
                setTimeout(() => {
                    resultCallback(onReject)
                })
            }
            // pending的回调(保存回调函数,暂不执行)
            if (this.PromiseState === "pending") {
                // 保存回调函数
                this.callback.push({
                    onResolved: function () {
                        resultCallback(onResolved)
                    },
                    onReject: function () {
                        resultCallback(onReject)
                    },
                })
            }
        })
    }

    // catch方法
    catch(onReject) {
        return this.then(undefined, onReject)
    }

    // resolve方法,类上的方法
    static resolve(value) {
         // 返回Promise对象
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                // 如果是Promise对象的话,直接返回Promise
                value.then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            } else {
                // 不是Promise对象的话,结果的对象状态为成功
                resolve(value)
            }
        })
    }

    static reject(reason){
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }

    static all(promises) {
        // 返回结果是Promise对象
        return new Promise((resolve, reject) => {
            // 遍历
            let count = 0;
            let arr = []
            for (let i = 0; i < promises.lengthy; i++){
                promises[i].then(v => {
                    // 三个Promise对象都成功才调用
                    count++
                    // 将当前Promise对象成功的结果存入到数组中
                    arr[i] = v
                    if (count === promises.length) {
                        resolve(arr)
                    }
                }, r => {
                    reject(r)
                })
            }

        }) 
    }

    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++){
                promises[i].then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            }
        })
    }  
}

  1. 使用
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./promise.js"></script>
  </head>
  <body>
    <script>
      // 这里的Promise是 ./promise.js 文件中的Promise
      let p = new Promise((resolve, reject) => {
        setTimeout(() => {
          // resolve("ok");
          reject("error");
        }, 1000);
      });

      console.log(p);

      const result = p
        .then((value) => {
          console.log(value);
        })
        .then((value) => {
          console.log(value);
        })
        .then((value) => {
          console.log(value);
        });
      console.log("result", result);
    </script>
  </body>
</html>

在这里插入图片描述

Async函数

  • 使用async修饰的函数的返回值是Promise对象
  • promise对象的结果由async函数执行的返回值决定(和then方法一致)
    eg:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      async function main() {
        // 如果返回值是非Promise类型的对象,那async函数的返回结果就是一个成功的Promise对象
        return 123;
        // 如果返回的是一个Promsie类型的对象, 那async函数的返回结果和当前Promise对象一致
        return new Promise((resolve, reject) => {
          resolve("ok");
        });

        // 如果抛出异常,那async函数的返回结果是一个失败的Promise对象,结果是抛出的内容
        throw "Oh No";
      }

      let result = main();
      console.log(result);
    </script>
  </body>
</html>

Await函数

  • await右侧的表达式一般为 promise对象,但也可以是其它的值(如基本数据类型等)
  • 如果表达式是promise对象, await返回的是promise 成功的值。(如果promise是失败的应该被catch捕获, await函数一般被try…catch…包裹)
  • 如果表达式是其它值,直接将此值作为 await的返回值

async和await

async和await的关系

  • await必须写在async,函数中,但async函数中可以没有await
  • 如果 await的 promise失败了,就会抛出异常,需要通过try...catch捕获处理
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      async function test() {
        let p = new Promise((resolve, reject) => {
          reject("ok");
        });
        //    右侧是Promise的情况
        try {
          await p;
        } catch (e) {
          console.log(e);
        }
      }
    </script>
  </body>
</html>

async和await的结合使用

async和await可以以同步的方式实现异步代码。简单地可以理解为await可以等待异步代码的执行,异步代码执行完之后再继续向下执行。但是实现以同步的方式实现异步代码的前提是await后面的函数返回值是Promise类型。

在async和await之前是使用回调函数的方式实现异步代码,回调函数嵌套回调函数:

fs.readFile('./1.html', (err, data)=>{
	fs.readFile('./2.html', (err, data)=>{
		……
	)
)

上述代码就会先读取完1.html再读取2.html

使用async和await:

await fs.readFile('./1.html')
await fs.readFile('./2.html')

上述代码也会先读取完1.html再读取2.html
eg1:

const { log } = require('console')
const fs = require('fs')

// 使用回调函数的方式实现
fs.readFile("./resource/1.html", (err, data1) => {
    if (err) throw err
    fs.readFile("./resource/2.html", (err, data2) => {
        if (err) throw err
        fs.readFile("./resource/3.html", (err, data3) => {
            if (err) throw err
            console.log(data1 + data2 + data3);
        })
    })
})


const util = require('util')
// util.promisify可以将API转换成返回值为Promise形式的格式
const mineReadFile = util.promisify(fs.readFile)
// async和await实现
async function main() {
    try {
        let data1 = await mineReadFile('./resource/1.html')
        let data2 = await mineReadFile('./resource/2.html')
        let data3 = await mineReadFile('./resource/3.html')
        console.log(data1 + data2 + data3);
    } catch (e) {
        console.log(e);
    }
    
}
main()

eg2:
async 和 await一般和AJAX请求结合使用,await后面一般接promise对象,所以我们一般使用axios封装的AJAX(返回值是Promise对象)进行接口的请求。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值