Promise入门

文章目录

  • ✨文章有误请指正,如果觉得对你有用,请点赞收藏关注一波,谢谢支持😘
  • 前言
  • 一、Promise的理解和使用
    • 1.Promise是什么?
      • 1.1.1 理解
      • 1.1.2 Promise 的状态改变
      • 1.1.3 Promise 的基本流程 图解
      • 1.1.4 Promise 的基本使用
      • 1.1.5 Promise 的小案例
    • 2.为什么要用 Promise?
      • 1.2.1 指定回调函数的方式更加灵活
      • 1.2.2 支持链式调用, 可以解决回调地狱问题
    • 3.如何使用 Promise
      • 1.3.1 构造函数Prototype方法 API
        • 1.3.1.0 构造函数 Promise (excutor) {}
        • 1.3.1.1 Promise.prototype.then 方法
        • 1.3.1.2 Promise.prototype.catch方法
      • 1.3.2 构造函数的API(4个方法)
        • 1.3.2.1 Resolve
        • 1.3.2.2 Reject
        • 1.3.2.3 All
        • 1.3.2.4 Race
      • 1.3.3 Promise 的几个关键方法
        • 1.3.3.1 如何改变 Promise 的状态?
        • 1.3.3.2 一个 Promise 指定多个成功/失败回调函数, 都会调用吗?
        • 1.3.3.3 改变 Promise 状态和指定回调函数谁先谁后❓
        • 1.3.2.4 Promise .then()返回的新 Promise 的结果状态由什么决定?
        • 1.3.2.5 Promise 如何串连多个操作任务?
        • 1.3.2.6 Promise 异常传透?
        • 1.3.2.7 如何中断 Promise 链?
      • 1.3.3 PromiseE8 之 async 和 await
        • 1.3.1 mdn 文档链接学习
        • 1.3.2 Async 函数
        • 1.3.3 await 表达式
        • 1.3.4 注意
    • 4.Promose开发注意事项
      • 注意Ⅰ🗿
      • 注意Ⅱ🗿
      • 注意Ⅲ🗿
    • 5.宏任务 & 微任务
      • 微队列的两个函数
      •    1、queueMicrotask
      •    2、mutationobserver
      •    练习题
  • 总结


✨文章有误请指正,如果觉得对你有用,请点赞收藏关注一波,谢谢支持😘

前言

谈到Promise,我们都知道它有一个pending属性,该属性有两种状态:成功(resolved/fulfilled)、失败(rejected),而且一个Promise只可能从“等待”转到“失败”或者“成功”;且状态一旦改变便是不可逆的,谈到Promise,很多人想到的就是解决回调地狱的问题,当我们在需要多个异步请求都执行完再执行下一步操作时,可以考虑使用promise。以下是个人学习Promise记录的知识点


一、Promise的理解和使用

1.Promise是什么?

1.1.1 理解

  • 抽象表达

    1. Promise 是一门新的技术( 规范) Promise 是 JS 中进行异步编程新解决方案.

    2. 备注:旧方案是单纯使用回调函数

  • 具体表达

    1. 从语法上来说: Promise 是一个构造函数
    2. 从功能上来说: Promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值都会有一个结果数据, 成功的结果数据一般称为 value, 失败的结果数据一般称为 reason

1.1.2 Promise 的状态改变

  1. pending 未定义
  2. pending 变为 resolved 成功
  3. pending 变为 rejected 😈response

1.1.3 Promise 的基本流程 图解

在这里插入图片描述

1.1.4 Promise 的基本使用

  • 抽奖Promise版本演示(基本使用)
const but=document.getElementById("but")
but.addEventListener("click",function (){let randomNumber=Math.ceil(Math.random()*100)//这里new Promiseconst p=new Promise(function (resolve, reject){	setTimeout(()=>{if(randomNumber<30){//成功的状态resolve("中奖了!")}else{//失败的的状态reject("抱歉,很遗憾!")}},1000)})p.then(value => {//这里是p的pending属性为resolve/fulfilledalert(value) //成功},reason => {//这里是p的pending属性为rejectedalert(reason) //失败})
})

1.1.5 Promise 的小案例

  1. 使用 Promise 封装基于定时器的异步

    function TimeDelay(time) {// 1. 创建 promise 对象return new Promise((resolve, reject) => {// 2. 启动异步任务console.log('启动异步任务')setTimeout(() => {console.log('延迟任务开始执行...')const time = Date.now() // 假设: 时间为奇数代表成功, 为偶数代表失败if (time % 2 === 1) { // 成功了// 3. 1. 如果成功了, 调用 resolve()并传入成功的 valueresolve('成功的数据 ' + time)} else { // 失败了// 3.2. 如果失败了, 调用 reject()并传入失败的 reasonreject('失败的数据 ' + time)}}, time)})
    }
    
  2. 使用 Promise 封装 ajax 异步请求

    {/* 可复用的发 ajax 请求的函数: xhr + promise */ }function PromiseAjax(url) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest()xhr.onreadystatechange = () => {if (xhr.readyState !== 4) returnconst { status, response } = xhr// 请求成功, 调用 resolve(value)if (status >= 200 && status < 300) {resolve(JSON.parse(response))} else { // 请求失败, 调用 reject(reason)reject(new Error('请求失败: status: ' + status))}}xhr.open("GET", url)xhr.send()})
    }
    
  3. 使用 Promise 封装基于定时器的异步

    function TimeDelay(time) {// 1. 创建 promise 对象return new Promise((resolve, reject) => {// 2. 启动异步任务console.log('启动异步任务')setTimeout(() => {console.log('延迟任务开始执行...')const time = Date.now() // 假设: 时间为奇数代表成功, 为偶数代表失败if (time % 2 === 1) { // 成功了// 3. 1. 如果成功了, 调用 resolve()并传入成功的 valueresolve('成功的数据 ' + time)} else { // 失败了// 3.2. 如果失败了, 调用 reject()并传入失败的 reasonreject('失败的数据 ' + time)}}, time)})
    }
    
  4. Promise实践练习-AJAX请求

    
    "en">"UTF-8">"viewport" content="width=device-width, initial-scale=1.0">Promise封装AJAX操作
    
    
    
  5. Promise封装练习-Fs模块

    /*** 封装一个函数 ReadFile 读取文件内容* 参数:  path  文件路径* 返回:  Promise 对象*/
    function ReadFile(path) {return new Promise((resolve, reject) => {//读取文件require('fs').readFile(path, (err, data) => {//判断if (err) reject(err);//成功resolve(data);});});
    }ReadFile('./resource/content.txt').then(value => {//输出文件内容console.log(value.toString());}, reason => {console.log(reason);});```
    
  6. Util.Promisify方法使用 API文档链接

    /*** util.promisify 方法	*/
    //引入 util 模块
    const util = require('util');
    //引入 fs 模块
    const fs = require('fs');
    //返回一个新的函数
    let mineReadFile = util.promisify(fs.readFile);  //返回Promise函数mineReadFile('./resource/content.txt').then(value => {console.log(value.toString());
    });
    

2.为什么要用 Promise?

1.2.1 指定回调函数的方式更加灵活

  • 旧的: 必须在启动异步任务前指定 createAudioFileAsync(audioSettings回调函数, successCallback, failureCallback)
  • Promise: 启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数(甚至可以任务结束后指定多个回调)

1.2.2 支持链式调用, 可以解决回调地狱问题

  • 什么是回调地狱❓
    • 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
  • 回调地狱的缺点❓
    • 不便于阅读
    • 不便于异常处理
  • 解终极解决方案
    • Promise链式调用 +async/await

3.如何使用 Promise

MDN官方 : https://developer.mozilla.org/promise

1.3.1 构造函数Prototype方法 API

1.3.1.0 构造函数 Promise (excutor) {}
  1. executor 函数: 执行器 (resolve, reject) => {}
  2. resolve函数: 内部定义成功时我们调用的函数 value => {}
  3. reject 函数: 内部定义失败时我们调用的函数 reason => {}
  4. 注意executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行 let Promise = new

Promise((resonse, reject) => console.log(22));//“同步调用执行”
||console.log(11);//控制台输出 22 11

1.3.1.1 Promise.prototype.then 方法
  • Promise.prototype.then方法:(onResolved(成功), onRejected(失败)) => {}
  1. onResolved 函数: 成功的回调函数 (value) => {}
  2. onRejected 函数: 失败的回调函数 (reason) => {}
  3. 说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason的失败回调
    返回一个新的 Promise 对象
1.3.1.2 Promise.prototype.catch方法
  • Promise.prototype.catch方法:(onRejected(失败)) => {}
  1. onRejected 函数: 失败的回调函数 (reason) => {}
  2. 说明: then()的语法糖, 相当于: then(undefined, onRejected)

1.3.2 构造函数的API(4个方法)

1.3.2.1 Resolve
let p1 = Promise.resolve(521);  //输出成功Promise对象  //resolve的参数问题:(以失败的状态为例)
let p2 = Promise.resolve(
new Promise((resolve, reject) => {// resolve('OK');reject("Error");
})
);
// 如果不对出错进行处理(指定错误回调),控制台就会报错
p2.then((value) => {
console.log(value);
},(reason) => {
console.log(reason);
});
console.log(p1)
console.log(p2)
  • 总结
  1. 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功Promise对象
  2. 如果传入的参数为 Promise 对象, 则Promise对象的状态决定了 Promise执行onResolve(成功)还是OnRejected(失败)

在这里插入图片描述

1.3.2.2 Reject
let p1 = Promise.reject(521);
let p2 = Promise.reject('haha');
let p3 = Promise.reject(new Promise((resolve, reject) => {resolve("OK");})
);console.log(p1)
console.log(p2)
console.log(p3);
  • 总结
  1. 如果传入的参数为 非Promise类型的对象, 则new Promise返回的结果始终为失败Promise

在这里插入图片描述

1.3.2.3 All
let p1 = new Promise((resolve, reject) => {resolve("OK");
});
let p2 = Promise.resolve('Success');
// let p2 = Promise.reject("Error");
let p3 = Promise.resolve("Oh Yeah");
const result = Promise.all([p1, p2, p3]);
console.log(result);
  • 总结

All方法:(这里以成功为例

说明: Promise.All(这里是一个数组,数组里面有一个一个的Promise),他返回一个新的 Promise, 只有所有的 Promise都成功才成功, 只要有一个失败了就直接失败。

在这里插入图片描述

1.3.2.4 Race
let p1 = new Promise((resolve, reject) => {setTimeout(() => {reject("OK");}, 1000);
});
let p2 = Promise.resolve("Error");
let p3 = Promise.resolve("Oh Yeah");
//调用
const result = Promise.race([p1, p2, p3]);
console.log(result);
  • 总结

race方法:(这里以成功为例

说明: 返回一个新的 Promise, 第一个完成的 Promise的结果状态就是最终的结果状

在这里插入图片描述

1.3.3 Promise 的几个关键方法

1.3.3.1 如何改变 Promise 的状态?
  • 改变 Promise 的状态的几种方法

代码演示

let p = new Promise((resolve, reject) => {//1. resolve 函数// resolve("ok"); // pending   => fulfilled (resolved)//2. reject 函数reject("error"); // pending  =>  rejected//3. 抛出错误// throw "出问题了";
});

在这里插入图片描述

1.3.3.2 一个 Promise 指定多个成功/失败回调函数, 都会调用吗?
  • 当 Promise改变为对应状态时都会调用

代码演示


let p = new Promise((resolve, reject) => {resolve("OK"); //如果注释掉resolve(),那么p的状态就还是pending,即状态未发生改变,不会调用then
});
///指定回调 - 1
p.then((value) => {console.log(value);
});
//指定回调 - 2
p.then((value) => {console.log(value);
});

在这里插入图片描述

1.3.3.3 改变 Promise 状态和指定回调函数谁先谁后❓
  • 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  • 如何先改状态再指定回调?
    • 在执行器中直接调用 resolve()/reject()
    • 异步任务 → 延迟更长时间才调用 then()
  • 什么时候才能得到数据?
    • 如果先指定的回调, 那需要等待状态发生改变时 去 执行回调函数, 得到数据 处理数据
    • 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据 处理数据

代码验证演示

let startTime = Date.now()
console.log("开始记时", startTime)
let p = new Promise((resolve, reject) => {setTimeout(() => {resolve("OK");let endTime = Date.now() - startTimeconsole.log("结束记时", endTime)}, 1000);
});
p.then((value) => {console.log(value);},(reason) => { }
);

在这里插入图片描述

1.3.2.4 Promise .then()返回的新 Promise 的结果状态由什么决定?
  • Promise .then()返回的新 Promise 的结果状态由什么决定?
  • 代码验证演示
    let p = new Promise((resolve, reject) => {resolve("ok");// reject("no");});//执行 then 方法let result = p.then((value) => {// console.log(value);//1. 抛出错误 rejected//   throw "出了问题";//2. 返回结果是非 Promise 类型的对象 fulfilled//   return 521;//3. 返回结果是 Promise 对象 fulfilled/rejectedreturn new Promise((resolve, reject) => {// resolve("success");reject("error");});},(reason) => {console.warn(reason);})console.log(result);// 这里result返回的依旧是一个Promise,以下是对Promise的成功或失败的处理let promise = result.then((value) => {console.log(value)}, (reason) => {return new Promise((resolve, reject) => {reject("失败了")})})console.log(promise)

说明: 代码的执行流程
举例 ↓
如果执行器里执行的是reject(),那么执行then的onRejected方法
如果onRejected方法返回非Promise对象,那么Promise .then()返回的新Promise的状态就为成功!
如果onRejected方法返回为Promise对象,那么该Promise返回的状态(成功或者失败/resolvereject)就决定了Promise .then()返回的新Promise的状态,同时1新Promise的值也就是返回Promise对象的参数值!。

在这里插入图片描述

1.3.2.5 Promise 如何串连多个操作任务?
  • Promise的 then()返回一个新的 Promise, 可以开成 then()的链式调用
  • 通过 then 的链式调用串连多个同步/异步任务
  • 代码验证演示
<script>let p = new Promise((resolve, reject) => {setTimeout(() => {resolve('OK');}, 1000);});p.then(value => {console.log(value);return new Promise((resolve, reject) => {resolve("success");});}).then(value => {console.log(value);}).then(value => {//因为上个then没有返回任何东西所以输出undefinedconsole.log(value);})
</script>

在这里插入图片描述

1.3.2.6 Promise 异常传透?
  • 当使用 Promise / 使用 then 链式调用时, 可以在最后指定失败的回调
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理 (只需在最后写Catch即可)
  • 代码验证演示
let p = new Promise((resolve, reject) => {setTimeout(() => {resolve('OK');// reject('Err');}, 1000);
});
p.then(value => {// console.log(111);throw '失败啦!';
}).then(value => {console.log(222);
}).then(value => {console.log(333);
}).catch(reason => { //用then也可以捕获异常,不过then要传两个参数console.warn(reason);
});
console.log(p)

在这里插入图片描述

1.3.2.7 如何中断 Promise 链?
  • 当使用 Promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法有却只有①种: 在回调函数中返回一个 pendding 状态的 Promise 对象
  • 代码验证演示

let p = new Promise((resolve, reject) => {setTimeout(() => {resolve('OK');}, 1000);
});
let a = p.then(value => {console.log(111);//有且只有一个方式return new Promise(() => {//返回一个pendding 状态的Promise});
}).then(value => {console.log(222);
}).then(value => {console.log(333);
}).catch(reason => {console.warn(reason);
});

1.3.3 PromiseE8 之 async 和 await

1.3.1 mdn 文档链接学习
  • Async https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

  • Await https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

1.3.2 Async 函数
  • 函数前面添加Async → 该函数的返回值为 Promise对象
  • Promise对象的结果由 Async 函数执行的返回值决定

async function main() {//1. 如果返回值是一个非Promise类型的数据 则状态为成功,返回一个成功的promise对象return 521;
}async function main1() {//2. 如果返回的是一个Promise对象 则状态取决于返回结果return new Promise((resolve, reject) => {// resolve('OK'); //成功reject("Error"); //失败});
}async function main2() {// 3. 抛出异常 返回一个失败的promise对象throw "Oh NO";
}
let result = main();
let result1 = main1();
let result3 = main2();
console.log(result);
console.log(result1);
console.log(result3);
1.3.3 await 表达式
  • await 右侧的表达式一般为 Promise对象, 但也可以是其它的值
  • 如果表达式是 Promise对象, await 返回的是 Promise成功的值
  • 如果表达式是其它值, 直接将此值作为 await 的返回值
1.3.4 注意
  • await 必须写在 async 函数中, 但 async 函数中可以没有 await
  • 如果 await 的 Promise失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
async function main() {let p = new Promise((resolve, reject) => {resolve("OK");// reject("Error");});//1. 右侧为promise的情况// let res = await p;//2. 右侧为其他类型的数据// let res2 = await 20;//3. 如果promise是失败的状态try {let res3 = await p;console.log(res3)} catch (e) {//catch捕获失败状态console.log(e);}
}

4.Promose开发注意事项

注意Ⅰ🗿

说明 : Async异步函数同时请求两条数据应该先使用all方法进行获取(执行效率大大提升)

async function f() {let promiseA = fetch("Path")let promiseB = fetch("Path")const [a, b] = await Promise.all([promiseA, promiseB]) (👍)//注意:await等待的过程中 js会去执行其他的代码 (底层使用 Promise + 事件机制)//......
}

注意Ⅱ🗿

说明 : 循环执行 Async异步任务时 不能使用Foreach,Map等方法

    // 异步函数并发执行async function f() {[1, 2, 3].forEach(async (element) => {await promiseFun1() //这里虽然使用了Await,但是ForEach会立刻返回,不会等待异步任务执行完})console.log("done");}async function f() {for (const i of [1, 2, 3]) {await promiseFun1()}console.log("done");}f()//酷炫写法 → 循环并发执行异步任务async function concurrence() {const promises = [promiseFun1(),promiseFun2(),promiseFun3()]for await (let result of promises) {//......}console.log("这里也会等待异步任务执行玩后输出!")}

总结:这里虽然使用了Await,但是ForEach会立刻返回,不会等待异步任务执行完

注意Ⅲ🗿

说明 :await 后面不能跟着普通函数

错误❌

await promiseFun1()

对 ✔

async function f(){await promiseFun1()
}
f()

5.宏任务 & 微任务

微队列的两个函数

  • 简介
  1. 任务是由(浏览器、Node)发起的,而微任务由 JS自身发起。
  2. 任务(Microtask)MutationObserver(浏览器环境)、 Promise.[ then/catch/finally ] 、queueMicrotask
  3. 事件队列process.nextTick(Node环境
  4. 任务的一般执行顺序:同步任务微任务宏任务

   1、queueMicrotask

说明:Window 或 Worker 接口的 queueMicrotask() 方法,queues a microtask to be executed at a safe time prior to control returning to the browser’s event loop.microtask 是一个简短的函数,它将在当前任务(task)完成其工作之后运行,并且在执行上下文的控制返回到浏览器的事件循环之前,没有其他代码等待运行。

语法:scope.queueMicrotask(function);

  • 参数
  1. function :微任务(microtask)的执行顺序在所有挂起的任务(pending tasks)完成之后,在对浏览器的事件循环产生控制(yielding control to the browser’s event loop)之前。
  2. 返回值:undefined。
  3. 示例self.queueMicrotask(() => { //函数内容 })

   2、mutationobserver

说明:MutationObserver接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

构造函数 : 创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。

  • 方法
  1. disconnect()
    说明 : 阻止 MutationObserver实例继续接收的通知,直到再次调用其 observe() 方法,该观察者对象包含的回调函数都不会再被调用。
  2. observe()
    说明 : 配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。
  3. takeRecords()
    说明 :从 MutationObserver 的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord对象的新 Array 中。

   练习题

  • 请说出下面的输出结果!
1. 遇到定时器setTimeout,放入(宏队列)
2. 遇到同步回调newPromise,直接执行输出
3. 遇到.then 将该部分放入(微任务)let a;const b = new Promise((resolve, reject) => {console.log('promise1');resolve();}).then(() => {console.log('promise2');}).then(() => {console.log('promise3');}).then(() => {console.log('promise4');});a = new Promise(async (resolve, reject) => {console.log(a);await b;console.log(a);console.log('after1');await aresolve(true);console.log('after2');});console.log('end');

在这里插入图片描述

总结

以上就是个人学习Promise的相关知识点,如有错漏之处,敬请指正。
以上是个人学习Promise的相关知识点,一点一滴的记录了下来,有问题请评论区指正,共同进步,这才是我写文章的原因之,如果这篇文章对您有帮助请三连支持一波👍


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部