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 理解
-
抽象表达
-
Promise 是一门新的技术
( 规范)Promise 是 JS 中进行异步编程的新解决方案. -
备注:
旧方案是单纯使用回调函数
-
-
具体表达
- 从语法上来说: Promise 是一个构造函数
- 从功能上来说: Promise 对象用来封装一个异步操作并可以获取其
成功/失败的结果值都会有一个结果数据, 成功的结果数据一般称为 value, 失败的结果数据一般称为 reason
1.1.2 Promise 的状态改变
- pending 未定义
- pending 变为 resolved
成功 - 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 的小案例
-
使用 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)}) } -
使用 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()}) } -
使用 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)}) } -
Promise实践练习-AJAX请求
"en">"UTF-8">"viewport" content="width=device-width, initial-scale=1.0">Promise封装AJAX操作 -
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);});``` -
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
- Promise链式调用 +
3.如何使用 Promise
MDN官方 : https://developer.mozilla.org/promise
1.3.1 构造函数Prototype方法 API
1.3.1.0 构造函数 Promise (excutor) {}
executor函数: 执行器 (resolve,reject) => {}resolve函数: 内部定义成功时我们调用的函数 value => {}reject函数: 内部定义失败时我们调用的函数 reason => {}注意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(失败)) => {}
- onResolved 函数: 成功的回调函数 (value) => {}
- onRejected 函数: 失败的回调函数 (reason) => {}
- 说明: 指定用于得到成功
value的成功回调和用于得到失败reason的失败回调
返回一个新的Promise对象
1.3.1.2 Promise.prototype.catch方法
- Promise.prototype.catch
方法:(onRejected(失败)) => {}
- onRejected 函数: 失败的回调函数 (reason) => {}
- 说明: 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)
- 总结
- 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功Promise对象
- 如果传入的参数为 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);
- 总结
- 如果传入的参数为 非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返回的状态(成功或者失败/resolve或reject)就决定了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.宏任务 & 微任务
微队列的两个函数
- 简介
宏任务是由(浏览器、Node)发起的,而微任务由JS自身发起。微任务(Microtask)MutationObserver(浏览器环境)、 Promise.[ then/catch/finally ] 、queueMicrotask事件队列process.nextTick(Node环境)- 任务的一般执行顺序:
同步任务→微任务→宏任务。
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);
- 参数
- function :微任务(microtask)的执行顺序在所有挂起的任务(pending tasks)完成之后,在对浏览器的事件循环产生控制(yielding control to the browser’s event loop)之前。
- 返回值:undefined。
- 示例
self.queueMicrotask(() => { //函数内容 });
2、mutationobserver
说明:MutationObserver接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。
构造函数 : 创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。
- 方法
- disconnect()
说明 : 阻止MutationObserver实例继续接收的通知,直到再次调用其 observe() 方法,该观察者对象包含的回调函数都不会再被调用。 - observe()
说明 : 配置MutationObserver在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。 - 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的相关知识点,一点一滴的记录了下来,有问题请评论区指正,共同进步,这才是我写文章的原因之,如果这篇文章对您有帮助请三连支持一波👍
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
