当前位置: 首页 > news >正文

promise深入理解和使用

概念

Promise是JS 中进行异步编程的新解决方案(旧的解决方案是回调函数),遵循es6规范。其最大特点就是解决了地狱回调问题。

从语法上来说: Promise是一个构造函数

从功能上来说: promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

异步编程包括
  • fs 文件操作

    require('fs').readFile('./index.html', (err,data)=>{})
    
  • 数据库操作

  • ajax

    $.get('/server', (data)=>{})
    
  • 定时器

    setTimeout(()=>{}, 2000);
    
优点

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

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

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

什么是回调地狱? 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
在这里插入图片描述

用法

基本写法
//promise构造函数的参数也是一个函数,接收两个参数,这两个参数也是函数
const p = new Promise((resolve, reject) => {//处理业务...//处理业务状态的结果if(res.status){resolve(res.response) //如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态}else{reject(res.status) //如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态}
});
p.then(res => { // 成功的回调函数 onResolved, 得到成功的 vlaue...},reason => { //失败的回调函数 onRejected, 得到失败的 reason...}
)
封装
function xxxxx(params) {//创建 promise 对象(pending 状态)return new Promise((resolve, reject) => {//处理业务...//处理业务状态的结果if(res.status){resolve(res.response) //如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态}else{reject(res.status) //如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态}});
}
//能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
xxxxx(params).then(res => { // 成功的回调函数 onResolved, 得到成功的 vlaue...},reason => { //失败的回调函数 onRejected, 得到失败的 reason...}
)

nodejs中有一个util.promisify方法可以自动帮我们封装promise业务。

promise状态

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

Promise 对象的值

实例对象中的另一个属性 『PromiseResult』

保存着异步任务『成功/失败』的结果

  • resolve
  • reject

执行流程

在这里插入图片描述

Promise的Api

Promise 构造函数: Promise (excutor){}

(1) executor 函数: 执行器 (resolve, reject) => {}

(2) resolve 函数: 内部定义成功时我们调用的函数 value => {}

(3) reject 函数: 内部定义失败时我们调用的函数 reason => {}

说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行

Promise.prototype.then 方法: (onResolved, onRejected) => {}

(1) onResolved 函数: 成功的回调函数 (value) => {}

(2) onRejected 函数: 失败的回调函数(reason) => {}

说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调 返回一个新的 promise 对象

Promise.prototype.catch 方法: (onRejected) => {}

(1) onRejected 函数: 失败的回调函数 (reason) => {}

说明: then()的语法糖, 相当于: then(undefined, onRejected)

Promise.resolve 方法: (value) => {}

(1) value: 成功的数据或 promise 对象

说明: 返回一个成功/失败的 promise 对象

//如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象,状态也是成功的
let p1 = Promise.resolve(521);
//如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {// resolve('OK'); // 返回 resolved / fullfilled 状态reject('Error'); // 返回 reject 状态
}));
// console.log(p2);
p2.catch(reason => {console.log(reason);
})
Promise.reject 方法: (reason) => {}

(1) reason: 失败的原因

说明: 返回一个一直是失败的 promise 对象 (这个对象为reject传入的参数,参数是啥,结果就是啥,状态都是失败的)

Promise.all 方法: (promises) => {}

(1) promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise对象。只有传入的所有的 promise 都成功,状态才是成功,返回的是传入的所有成功的promise对象。只要有一个失败了返回的promise状态就是失败,结果为传入的失败的promise对象。

Promise.race 方法: (promises) => {}

(1) promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise对象, 第一个完成的 promise 的结果状态就是最终的结果状态。这里完成意思是传入n 个 promise 的数组, 哪一个优先成为promise对象,哪一个就决定了返回对象的结果和状态。

let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('OK');}, 1000);
})
let p2 = Promise.resolve('Success'); 
let p3 = Promise.resolve('Oh Yeah');
//调用
const result = Promise.race([p1, p2, p3]);//因为p1 1秒后才执行,所以返回的结果为p2,状态也由p2决定
console.log(result);

关键的问题

如何改变 promise 的状态?
const p = new Promise((resolve, reject) => {//resolve(value);//如果当前是 pending 就会变为 resolved//reject(reason); //如果当前是 pending 就会变为 rejected throw "sss"; //如果当前是 pending 就会变为 rejected, 值为"sss"
})
console.log(p1)
一个 promise 指定多个成功/失败回调函数, 都会调用吗?

当 promise 改变为对应状态时都会调用

改变 promise 状态和指定回调函数谁先执行谁后执行?

两种都有可能。如何先改状态再指定回调?

  • 在执行器中(excutor)直接调用 resolve()/reject(),然后才调用回调
  • 延迟更长时间调用 then()。比如执行器中延时1秒执行,then中延时两秒。

什么时候then先执行?

  • 执行器调用resolve()/reject()由延时,或者比then延时更长。就会调用then方法。

如果then先执行什么时候才能得到数据?

  • 只有当执行器调用resolve()/reject()完毕之后,then方法的回调(作为then方法的那两个参数)才会执行
promise.then()返回的新 promise 的结果状态由什么决定?

调用then方法,then方法的逐回结果是 Promise对象,对象状态由回调函数的执行结果决定。

  1. 如果回调函数中返回的结果是非promise 类型的属性,状态为成功,返回值为对象的成功的值.
  2. 如果回调函数中返回的结果是promise 类型的属性,状态根据then方法内部Promise返回的状态决定。
  3. 如果直接抛出错误,返回值也是promise类型的,状态是reject,值为抛出错误的值。
//创建实例
const p = new Promise(function (resolve, reject) {//模拟主体业务代码setTimeout(() => {//let data = "成功获取数据库中的数据";//resolve(data);let data = "获取失败";reject(data);}, 1000);
});
//调用promise实例
const result = p.then(function (value) {//1.非promise类型的属性return 'iloveyou';//2.是 promise对象return new Promise((resolve, reject) => {// resolve('ok');reject('error ');});//3.抛出错误throw new Error("出错啦!");
}, function (reason) {console.warn(reason);
});
console.log(result);

由于promise返回的是promise类型,所以可以进行链式调用

const fs = require('fs');const p = new Promise(function (resolve, reject) {fs.readFile("./source/为学.md", function (err, data) {if (err) reject(err);resolve(data);});
});p.then(value => {return new Promise((resolve, reject) => {fs.readFile("./source/为学1.md", function (err, data) {resolve([value, data]);});});
}).then(value => {return new Promise((resolve, reject) => {fs.readFile("./source/为学2.md", function (err, data) {value.push(data);return resolve(value);});});
}).then(value => {console.log(value.join('\r\n'));
});
promise 异常传透?

(1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调

(2) 前面任何操作出了异常, 都会传到最后失败的回调中处理

p.then(value => {throw '失败啦!';console.log(222);
}).then(value => {console.log(333);
}).catch(reason => {console.warn(reason);
});

中断 promise 链?

  • 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

自定义封装Promise

function Promise(executor){this.PromiseState = "pending"this.PromiseResult = nullthis.callback = []//保存Promise对象到this中const _this = this;function resolve(data){//只能修改一次if(_this.PromiseState !== "pending") return;//更改状态和值_this.PromiseState = "fulfilled"_this.PromiseResult = data//如果有保存then方法的参数回调,就执行if(_this.callback){_this.callback.forEach(item=>{item.onResovle(data)})}}function reject(data){//只能修改一次if(_this.PromiseState !== "pending") return;//更改状态和值_this.PromiseState = "reject"_this.PromiseResult = data//如果有保存then方法的参数回调,就执行if(_this.callback.onReject){_this.callback.onReject(data)}//如果有保存then方法的参数回调,就执行if(_this.callback){_this.callback.forEach(item=>{item.onReject(data)})}}try {//同步调用『执行器函数』executor(resolve, reject);} catch (error) {reject(error)}}Promise.prototype.then = function(onResovle, onReject){let _this = this//如果沒有传递onReject参数if(typeof onReject !== "function"){onReject = reason => {throw reason}}//如果沒有传递onResovle参数if(typeof onResovle !="function"){onResovle = value => value}//返回一个Promise对象return new Promise((resolve, reject)=>{function callback(type){try {const result = type(_this.PromiseResult)if(result instanceof Promise){result.then(v=>{resolve(v)}, r=>{reject(r)})}else{resolve(result)}} catch (error) {reject(error)}}if(this.PromiseState === "fulfilled"){callback(onResovle)}if(this.PromiseState === "reject"){callback(onReject)}if(this.PromiseState === "pending"){//状态为pending的时候保存回调方法this.callback.push({onResovle:function(){callback(onResovle)}, onReject:function(){callback(onReject)}})}})
}Promise.prototype.catch = function(onReject){return this.then(undefined, onReject)
}Promise.resolve = function(value){return new Promise((resolve, reject)=>{if(value instanceof Promise){value.then(r=>{resolve(r)}, v=>{reject(v)})}else{resolve(value)}})
}Promise.reject = function(value){return new Promise((undefined, reject)=>{reject(value)})
}Promise.all = function(promise){return new Promise((resolve, reject)=>{let count = 0let arr = []for(let i=0; i<=promise.length; i++){promise[i].then(v=>{count ++;arr[i] = v;if(count === promise.length){resolve(arr)}}, r=>{reject(r);})}})
}Promise.race = function(promise){return new Promise((resolve, reject)=>{for(let i=0; i<=promise.length; i++){promise[i].then(v=>{resolve(v)}, v=>{reject(v);})}})
}

async和await

文档

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

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

async函数
  • async关键字修饰的函数的返回值为promise对象。

  • promise对象的结果由async函数执行的返回值决定

函数体内部返回的结果如果是一个非Promise类型的对象,调用函数后返回的结果就是成功Promise对象,promise对象的值为返回的值。

async function fn() {return 'success';
}
let result = fn();
console.log(result);

如果函数体内抛出错误, 调用函数后返回的结果是一个失败的 Promise。

async function fn() {throw new Error('出错啦');
}
let result = fn();
console.log(result);

如果函数体内返回是一个Promise对象。

async function fn() {return new Promise(function (resolve, reject) {//在Promise对象中如果执行resolve函数,async函数将返回成功的Promise对象,值为resolve传递的参数。//在Promise对象中如果执行reject函数,函数将返回失败的Promise对象,值为resolve传递的参数});
}
let result = fn();
console.log(result);

await表达式

await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值。

  • await必须写在 async函数中
  • await右侧的表达式一般为promise对象
  • await返回的是promise 成功的值
  • awaitpromise 失败了,就会抛出异常,需要通过try...catch捕获处理。
//创建promise对象
const p = new Promise((resolve, reject) => {// resolve("用户数据");reject("失败啦! ");
})
// await要放在async函数中
async function main() {try {let result = await p;//await返回的是promise 成功的值console.log(result);} catch (e) { //如果调用reject函数,捕获异常console.log(e);}
}
//调用函数
main();

async和await结合实践

const fs = require('fs');function readWeiXue1() {return new Promise((resolve, reject) => {fs.readFile("./source/为学.md", function (err, data) {if (err) reject(err);resolve(data);})});
}function readWeiXue2() {return new Promise((resolve, reject) => {fs.readFile("./source/为学1.md", function (err, data) {if (err) reject(err);resolve(data);})});
}function readWeiXue3() {return new Promise((resolve, reject) => {fs.readFile('./source/为学2.md', function (err, data) {if (err) reject(err);resolve(data);})});
}async function main() {let wx1 = await readWeiXue1();let wx2 = await readWeiXue2();let wx3 = await readWeiXue3();console.log(wx1.toString());console.log(wx2.toString());console.log(wx3.toString());
}
main();

async和await结合ajax实践

function sendAjax(method, url) {return new Promise((resolve, reject) => {//创建对象let xhr = new XMLHttpRequest();//初始化xhr.open(method, url);//发送xhr.send();//事件绑定xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.response)} else {reject(xhr.status);}}}})
}async function main() {let l1 = await sendAjax("GET", "https://www.tianqi.com/tianqi/mapdata_new.json");console.log(l1);
}
main();
http://www.lryc.cn/news/576778.html

相关文章:

  • Bugku——WEB篇(持续更新ing)
  • 【windows如何使用rsync支持断点续传】
  • OSPF(开放最短路径优先)
  • 【记录】服务器多用户共享Conda环境——Ubuntu24.04
  • Windows环境下C语言汇编语言编辑器及环境安装
  • 提升JavaScript性能的六大关键策略
  • 博图SCL编程利器:CASE OF 语句详解与应用指南之设备运行模式选择框架
  • [面试] 手写题-数组转树
  • VS2022-动静态库
  • (LeetCode 面试经典 150 题 ) 134. 加油站 (贪心)
  • MATLAB GUI界面设计 第七章——高级应用
  • 大数据Hadoop之——安装部署hadoop
  • Wpf布局之StackPanel!
  • 【Java EE初阶 --- 多线程(进阶)】锁策略
  • Git常见使用
  • 现代 JavaScript (ES6+) 入门到实战(四):数组的革命 map/filter/reduce - 告别 for 循环
  • 【记录】Ubuntu创建新用户,并可远程连接
  • 【大语言模型入门】—— 浅析LLM基座—Transformer原理
  • 自然语言处理NLP期末复习
  • 解锁云原生微服务架构:搭建与部署实战全攻略
  • 小米路由器 AX3000T自定义子网掩码
  • 大模型小模型选型手册:开源闭源、国内国外全方位对比
  • AtCoder Beginner Contest 412
  • 2025.6GESP四级(编程题详解)
  • 基于云的平板挠度模拟:动画与建模-AI云计算数值分析和代码验证
  • 鸿蒙5:自定义构建函数
  • 提示技术系列——生成知识提示
  • HTTP中常见的Content-Type
  • 【HuggingFace】模型选型策略指南(读懂config.json)
  • RAG工作原理