前端Promise总结笔记丨【WEB前端大作战】

网友投稿 681 2022-05-30

一.什么是Promise:

Promise 是在 js 中进行异步编程的新解决方案。(以前旧的方案是单纯使用回调函数)

从语法来说,promise是一个构造函数。

从功能来说,promise对象用来封装一个异步操作,并且可以获得成功或失败的返回值。

JS中的常见的异步操作:定时器,AJAX中一般也是异步操作(也可以同步),回调函数可以理解为异步(不是严谨的异步操作)…等。

剩下的都是同步处理

二.为啥使用Promise:

promise使用回调函数更灵活。旧的回调函数必须在启动异步任务前指定。

promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至能在异步任务结束后指定多个)

promise支持链式调用,可以解决回调地狱问题。(回调地狱就是多层回调函数嵌套使用,就是套娃,这样就不利于阅读和异常处理。)

三. promise初体验:

效果:点击一个按钮,有30%概率显示中奖。

实现: 点击按钮后得到一个1到100间的随机数,小于等于30输出中奖,否则输出没中。期间用定时器模拟异步操作,在定时器里执行判断。

(1)基础的写法:

(2)promise写法,在promise里封装一个异步操作。

promise封装:

// 点击事件 btn.addEventListener('click',function(){ const p = new Promise((resolve,reject) => { //创建对象 const xhr = new XMLHttpRequest(); //初始化 xhr.open('GET', "http://poetry.apiopen.top/sentences"); //发送 xhr.send(); //处理响应结果 xhr.onreadystatechange = function () { 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.warn(reason); }) })

若把接口写错:

五:Promise封装ajax请求:

跟上一步差不多。就是把其封装在一个sendAJAX()的自定义函数里。

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(xhr.status); } } } }); } sendAJAX("http://poetry.apiopen.top/sentences") .then(value=>{ console.log(value); },reason=>{ //控制台输出警告信息 console.warn(reason); })

六:promise的状态改变:

promise状态表示实例对象的一个属性【PromiseState】。包括以下值:

(1)pending 未决定的

(2)resolved 或 fullfilled 成功

(3)rejected 失败

Promise对象的值表示实例对象的另一个属性【PromiseResult】。保存着对象【成功/失败】的结果。而其状态改变只有以下两种可能:

(1)pending 变为resolved

(2)pending 变为 rejected

注:一个promise对象只能改变一次,无论成功或失败都会有一个结果数据,成功的称为 value , 失败的称为 reason 。

七:Promise基本流程图:

八:Promise的API 使用:

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

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

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

注意:Promise内部会立同步即调用executor,异步操作在执行器里执行。

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

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

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

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

注:只是失败的调用。then()的语法糖,相当于: then(undefined, onRejected)。

value: 成功的数据或promise对象

注:如果传入的参数为非Promise类 型的对象,则返回的结果为成功promise对象,如果传入的参数为Promise 对象,则参数的结果决定了resolve 的结果。

reason: 失败的原因

注:无论传入啥只返回一个失败的promise对象。

promises: 包含n个promise的数组

注:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败。失败了返回那个失败值。

promises: 包含n个promise的数组

注:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态。

来一个例子:

let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('yes'); },1000) }) let p2 = Promise.resolve('success'); let p3 = Promise.resolve('come'); const result = Promise.race([p1,p2,p3]); console.log(result);

九:使用Promise面临的关键问题:

(1) resolve(value): 如果当前是pending就会变为resolved。

(2) reject(reason): 如果当前是pending就会变为rejected。

(3)抛出异常 throw :如果当前是pending就会变为rejected。

let p1 = new Promise((resolve,reject)=>{ // resolve('success'); // reject('error'); // throw 'error'; })

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

let p = new Promise((resolve,reject)=>{ resolve('success'); }) // 第一次回调 p.then(value=>{ console.log("yes"); }) // 第二次回调 p.then(value=>{ console.log("oh yes"); })

3.改变 promiseT状态和指定回调函数谁先谁后?

(1)都有可能, 正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

(2)如何先改状态再指定回调?

①在执行 器中直接调用resolve(/reject();

②延迟更 长时间才调用then();

(3)什么时候才能得到数据?

①如果先指定的回调, 那当状态发生改变时,回调函数就会调用,得到数据

②如果先改变的状态, 那当指定回调时,回调函数就会调用,得到数据

(1)简单表达: then()指定的回调函数执行的结果决定。

(2)详细表达:

*如果抛出异常, 新promise变为rejected, reaon为抛出的异常。

*如果返回的是非prormise的任意值,新promise变为resolved, value为返回的值。

*如果返回的是另一个新promise,此promise的结果就会成为新promise的结果。

随笔:

let p = new Promise((resolve,reject) => { // resolve('success'); // reject('No'); // throw 'oh no'; }); let result = p.then(value => { console.log(value); }, reason => { console.warn(reason); }); console.log(result);

(1) promise 的then()返回一个新的promise,可以开成then()的链式调用。

(2)通过then的链式调用串连多个同步/异步任务。

let p =new Promise((resolve,reject) => { resolve("yes"); }) p.then(value => { return new Promise((resolve,reject)=>{ resolve("oh yes~"); }); }).then(value => { console.log(value); })

输出结果:

oh yes~

let p =new Promise((resolve,reject) => { resolve("yes"); }) p.then(value => { return new Promise((resolve,reject)=>{ resolve("oh yes~"); }); }).then(value => { console.log(value); }).then(value => { console.log(value); })

输出结果:

oh yes~

undefined

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

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

let p =new Promise((resolve,reject) => { setTimeout(()=>{ resolve("yes"); },1000); }) p.then(value => { throw 'oh No'; }).then(value => { console.log("123"); }).then(value => { console.log("456"); }).catch(reason=>{ console.warn(reason); })

输出结果:

oh No

(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。

(2)办法:在回调函数中返回一个pendding状态的promise对象。

未中断:

let p =new Promise((resolve,reject) => { setTimeout(()=>{ resolve("yes"); },1000); }) p.then(value => { console.log("789"); }).then(value => { console.log("123"); }).then(value => { console.log("456"); }).catch(reason=>{ console.warn(reason); })

输出结果:

789

123

前端Promise总结笔记丨【WEB前端大作战】

456

中断:

let p =new Promise((resolve,reject) => { setTimeout(()=>{ resolve("yes"); },1000); }) p.then(value => { console.log("789"); return new Promise(()=>{}); }).then(value => { console.log("123"); }).then(value => { console.log("456"); }).catch(reason=>{ console.warn(reason); })

输出结果:

789

十:Promise的自定义封装:

封装:

class Promise{ //构造方法 constructor(executor) { //添加状态属性与结果值属性 this.PromiseState = 'pending'; this.PromiseResult = null; // 定义callback属性,保存pending状态的回调函数 this.callbacks = []; //保存实例对象的this值 const that = this; //自定义resolve函数,名字不一定用resolve function resolve(data) { //判断状态是否修改过 if (that.PromiseState !== 'pending') return; //改变状态属性 that.PromiseState = 'fulfilled'; // 或者 resolve //改变结果值属性 that.PromiseResult = data; //异步任务成功后执行回调函数 setTimeout(() => { that.callbacks.forEach(item => { item.onResolved(data); }) }); } //自定义reject函数 function reject(data) { //判断状态是否修改过,改过就直接返回 if (that.PromiseState !== 'pending') return; //改变状态属性 that.PromiseState = 'rejected'; //改变结果值属性 that.PromiseResult = data; //异步任务失败后执行回调函数 setTimeout(() => { that.callbacks.forEach(item => { item.onRejected(data); }) }); } try{ //同步调用【执行器函数】 executor(resolve,reject); }catch(e){ //更改Promise对象为失败 reject(e); } } //then方法封装 then(onResolved,onRejected){ const that = this; //判断回调参数是否存在 if(typeof onRejected !== 'function'){ onRejected = reason =>{ throw reason; } } if(typeof onResolved !== 'function'){ onResolved = value => value; } return new Promise((resolve, reject) => { //封装重复的部分 function callback(type){ try { //将结果值传入 let result = type(that.PromiseResult); //判断 if (result instanceof Promise) { //如果是Promise对象 result.then(v => { resolve(v); }, r => { reject(r); }) } else { //结果对象状态为【成功】 resolve(result); } } catch (e) { reject(e); } } //如果Promise状态为fulfilled回调这个函数 if (this.PromiseState === 'fulfilled') { setTimeout(()=>{ callback(onResolved); }); } //如果Promise状态为rejected回调这个函数 if (this.PromiseState === 'rejected') { setTimeout(()=>{ callback(onRejected); }); } //如果Promise状态为pending,保存回调函数 if (this.PromiseState === 'pending') { this.callbacks.push({ onResolved: function () { callback(onResolved); }, onRejected: function () { callback(onRejected); } }) } }) } //catch 方法 catch(onRejected){ return this.then(undefined,onRejected); } //resolve方法 static resolve(value){ //返回promise对象 return new Promise((resolve,reject) =>{ if(value instanceof Promise){ value.then(v=>{ resolve(v); },r=>{ reject(r); }) }else{ resolve(value); } }) } //reject方法 static reject(reason){ return new Promise((resolve,reject)=>{ reject(reason); }); } //all方法 static all(promises) { return new Promise((resolve, reject) => { //添加变量 let count = 0; // 存放成功结果数组 let arr = []; //遍历全部 for (let i = 0; i < promises.length; i++) { promises[i].then(v => { //能进到证明其为成功 count++; //保存成功结果 arr[i] = v; //如果全部成功 if (count === promises.length) { //状态为成功 resolve(arr); } }, r => { //能进到证明其为失败 reject(r); }); } }); } //race方法 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); }) } }); } }

十一:async函数:

MDN文档

1.函数的返回值为promise对象。

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

3.其实跟 then()方法返回结果是一样一样的。

async function main(){ return '123'; } let res = main(); console.log(res);

如:

async function main(){ return new Promise((resolve,reject)=>{ reject('NO'); }); } let res = main(); console.log(res);

async function main(){ return new Promise((resolve,reject)=>{ reject('NO'); }); } let res = main(); console.log(res);

十二.await表达式:

MDN文档

1.await右侧的表达式一般为promise对象,但也可以是其它的值。

2.如果表达式是promise对象,await返回的是promise成功的值。

3.如果表达式是其它值,直接将此值作为await的返回值。

注意:

1.await 必须写在async函数中,但async 函数中可以没有await 。

2.如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理。

async function works(){ let p = new Promise((resolve,reject)=>{ resolve('oh yes') }) let res = await p; console.log(res); } works();

结果:

oh yes

async function works(){ let p = new Promise((resolve,reject)=>{ resolve('oh yes') }) // let res = await p; let res = await 100; console.log(res); } works();

结果:

100

async function works(){ let p = new Promise((resolve,reject)=>{ // resolve('oh yes') reject('err'); }) try{ let res = await p; }catch(e){ console.log(e); } } works();

十三.async与await结合发生ajax请求:

效果: 点击按钮获取一句名言。

Document

十四.总结:

我只想说…

【WEB前端大作战】火热进行中:https://bbs.huaweicloud.com/blogs/255890

JavaScript VsCode web前端

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:图文并茂将HTML5中的新增表单元素彻底搞明白
下一篇:Python 中更优雅的日志记录方案
相关文章