-
Pronise介绍与基本使用
-
Promise的定义:
概念表达:Promise是一门新的技术,用来解决JS中进行异步编程的新的解决方案
技术表达:Promise是一个构造函数,用来封装一个异步操作,并且可以获取其成功/失败的结果值。
-
常见异步操作
- fs读写文件
require('fs').readfile('../index.js','utf-8',(err,data)=>{})
- 数据库操作(例如,mysql模块中的db.querry)
require('mysql').querry('select * from users',(err,resluts)=>{})
- Ajax数据请求操作
$.get('/api',(data)=>{})
- 定时器
setTimeout(()=>{},1000)
-
为什么要使用Promise
3.1 支持链式调用,可以解决回地狱的问题
- 回调地狱:回调函数的嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件。
- 回调函数的确定:①层层嵌套,不便于阅读②不变域异常处理
- 解决方案:①Promise链式调用
3.2 指定回调函数的方式更加灵活
- 旧的回调函数:必须在启动异步任务前指定
- promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后,指定多个回调函数)
-
Promise封装小案例
- 封装Ajax请求
/* 封住一个发送sendAjax发送GET Ajax请求 参数 URL 返回 Promise对象 */ function sendAjax(url){ return new Promise((resovle,reject)=>{ const xhr = new XMLHttpRequest(); xhr.open("GET",url); xhr.responseType = 'json'; xhr.send(); xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ // 判断成功 if(xhr.status >= 200 &&xhr.status<=400){ resovle(xhr.response) } else{ reject(xhr.status) } } } }) } sendAjax('https://api.apiopen.top/api/sentences').then(res=>{ console.log(res) },err=>{ console.warn(err) })
- 封装fs模块
function readFile(path,method){ return new Promise((resolve,reject)=>{ require('fs').readFile(path,method,(err,data)=>{ // 判断,如果出现错误 if(err) reject(err); // 成功 resolve(data) }) }) } readFile('./a.txt','utf-8').then( value=>{ console.log(value) }, reason=>{ console.log(reason) } );
- util.promisify
/* util.promisify方法 */ const util = require('util') const fs = require('fs'); // 返回一个promise风格的函数 let readFiles = util.promisify(fs.readFile) readFiles('./a.txt').then(value=>{ console.log(value.toString()) })
状态:实例对象的一个属性PromiseState
- pendding 未决定的
- resolved / fulfilled 成功
- rejected 失败
实例对象中的另一个属性PromiseResult,保存的是对象异步操作成功/失败的结果,resolve和reject可以对属性PromiseResult进行修改
7. #### Promise的基本流程
new Promise()[pendding状态]-----(执行异步操作)----->成功,执行resolve----->Promise对象[resolved]----->新的Promise对象 -
-
PromiseAPI
-
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)=>{}
-
Promise.resolve方法:(value)=>{}
(1)value:成功的数据或promise对象
说明:
①如果传入的参数为非Promise类型的对象,则返回的结果为成功Promise对象 ②如果传入的参数 为Promsie对象,则参数的结果决定了resolve的结果
-
Promise.reject 方法:(reason) =>{}
(1)reason:失败的原因
说明:
返回一个失败的promise对象 -
Promise.all方法:(promises) =>{}
(1) promises:包含n个promise的数组
说明:
返回一个新的 promise,只有所有的 promise都成功才成功,只要有一个失败了就直接失败 -
Promise.race方法: (promises) =>{}
(1)promises:包含n个promise的数组
说明:
返回一个新的 promise,由第一个先改变状态的 promise的结果状态就是最终的结果状态
3.1. 如何改变promise的状态
(1) resolve(value):如果当前是pending就会变为resolved
(2)reject(reason):如果当前是pending就会变为rejected
(3)抛出异常:如果当前是pending就会变为rejected
3.2. 一个Promise指定多个成功/失败回调函数,都会调用吗?
- 当Promise改变状态是对应状态的回调都会调用
3.3. 改变Promise状态和指定回到函数谁先谁后?
(1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
- 在执行器中直接调用resolve()/reject()
- 延迟更长时间才调用then()
(3)什么时候才能得到数据?
- 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
3.4. promise.then()返回的新promise的结果状态由什么决定?
- 简单表达:由then()指定的回调函数执行的结果决定‘
- 详细表达:
- 如果得抛出异常,新promise变为rejected,reason为抛出的异常
- 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
- 如果返回的是另一个新的Promise,此时then的Promise结果就会变成新的promise的结果
3.5.promise如何串连多个操作任务?
(1)promise的 then()返回一个新的promise,可以开成 then()的链式调用
(2)通过 then的链式调用串连多个同步/异步任务
3.6. Promise异常穿透
(1)当使用promise的 then链式调用时,可以在最后指定失败的回调
(2)前面任何操作出了异常,都会传到最后失败的回调中处理
3.7. 中断Promise链
(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
(2)解决办法:在回调函数中返回一个pendding 状态的 promise对象
原因:
因为返回的是pendding状态的Promise对象,then的返回值为pendding状态的Promise对象,由于状态没有改变,所以后续的resolved和rejected状态的回调函数都不会执行
-
Promise自定义封装
class Promise { // 构造方法 constructor(executor) { // 添加属性 this.PromiseState = 'pendding'; this.PromiseResult = null; this.callbacks = []; const that = this; // resolve函数 function resolve(data) { // 判断状态 if (that.PromiseState !== "pendding") return; // 1.修改Promise的状态(PromiseState) that.PromiseState = 'fulfilled'; // 2.设计Promise对象结果值(PromiseResult) that.PromiseResult = data // 调用成功的回调函数 // 应该执行多个成功的回调函数 setTimeout(() => { that.callbacks.forEach(v => { v.onResovled(data); }); }) }; // reject函数 function reject(data) { // 判断状态 if (that.PromiseState !== "pendding") return; // 1.修改Promise的状态(PromiseState) that.PromiseState = 'rejected'; // 2.设计Promise对象结果值(PromiseResult) that.PromiseResult = data // 调用失败的回调函数 // 应该执行多个失败的回调函数 setTimeout(() => { that.callbacks.forEach(v => { v.onRjected(data); }); }) }; try { // 执行器函数在Promise内部是同步调用的 executor(resolve, reject) } catch (err) { // 修改Promise的状态为失败 reject(err); } } // then方法封装 then(onResovled, onRjected) { const that = this; // 判断回调函数 if (typeof onRjected !== 'function') { onRjected = reason => { throw reason; } } if (typeof onResovled !== 'function') { onResovled = value => value // value=>{ return value } } return new Promise((resolve, reject) => { // 封装函数 function callback(funtype) { try { // 获取回调函数的执行结果 let res = funtype(that.PromiseResult); // 判断 if (res instanceof Promise) { // 如果是Promise类型的对象 res.then(res => { resolve(res); }, err => { reject(err); }) } else { //返回成功状态的Promise resolve(res) } } catch (err) { reject(err) } } // 调用回调函数 if (this.PromiseState === "fulfilled") { setTimeout(() => { callback(onResovled); }) } if (this.PromiseState === "rejected") { setTimeout(() => { callback(onRjected); }) } // 判断pendding状态 if (this.PromiseState === "pendding") { // 保存回调函数 this.callbacks.push( { onResovled: function () { callback(onResovled); }, onRjected: function () { callback(onRjected) } } ) } }) } // catch方法 catch(onRjected) { return this.then(undefined, onRjected); } // 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) { //返回的结果为Promise对象 return new Promise((resolve, reject) => { // 声明变量 let count = 0; let arr = []; for (let i = 0; i < promises.length; i++) { promises[i].then(v => { // 每个Promise都成功 count++; // 将当前Promise对象成功的结果存入数组中 arr[i] = v; if (count === promises.length) { resolve(arr); // count = 0; } }, e => { reject(e); }) } }); } // 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与await
-
async函数
-
async函数的返回值为promise对象
-
promise对象的结果由async函数执行的返回值决定
①如果返回值是一个非Promise类型的数据,那么整个函数返回的就是一个成功的Promise对象
②如果返回的是一个Promise对象,那么整个函数返回的就是的Promise对象的状态
-
-
await表达式
- await右侧的表达式一般为promise对象,但也可以是其它的值
- 如果表达式是promise对象, await返回的是promise成功的值
- 如果表达式是其它值,直接将此值作为 await的返回值
注意:
-
await必须写在nsync函数中,但snync函数中可以没有await
-
如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
let p = new Promise((resolve,reject)=>{ // resolve("OK") reject("Error") }) // let res= await p; try { let res= await p; } catch (e) { console.log(e) }
3.async和await结合小案列
function sendAjax(url) { return new Promise((resovle, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = 'json'; xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { // 判断成功 if (xhr.status >= 200 && xhr.status <= 400) { resovle(xhr.response) } else { reject(xhr.status) } } } }) } var btn1 = document.getElementsByClassName('btn')[0]; btn1.addEventListener('click', async function () { // 获取信息 let res = await sendAjax('https://XXX') console.log(res) })
-