目录
介绍
概念
特点:
缺点:
理解
基本流程
体验使用
抽奖案例
传统方式
promise方式:
读取文本案例
传统模式
promise方式
发送ajax请求
传统方式
promise方式
Promise的属性
promise的状态
promise 对象的值
Promise的Api
Promise关键点
Promise如何修改对象的状态
Promise是异步编程的一种解决方案
,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
通俗讲,Promise是一个许诺、承诺
,是对未来事情的承诺,承诺不一定能完成,但是无论是否能完成都会有一个结果。
Promise 用来预定一个不一定能完成的任务,要么成功,要么失败
在具体的程序中具体的体现,通常用来封装一个异步任务,提供承诺结果
Promise 是异步编程的一种解决方案,主要用来解决回调地狱的问题,可以有效的减少回调嵌套
。真正解决需要配合async/await
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。
(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。和一般的对象不一样,无需调用。
(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
(3)当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
抽象表达:
Promise 是一门新的技术(ES6 规范)
Promise 是 JS 中
进行异步编程
的新解决方案 备注:旧方案是单纯使用回调函数具体表达:
从语法上来说: Promise 是一个
构造函数
从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值
promise 的状态
实例对象中的一个属性 『PromiseState』
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败
promise 的状态改变
pending 变为 resolved
pending 变为 rejected
说明:
只有这 2 种
, 且一个 promise 对象只能改变一次
无论变为成功还是失败, 都会有一个结果数据 成功的结果数据一般称为 value, 失败的结果数据一般称为 reason
* 点击抽奖按钮 弹出窗口显示是否中奖(30%概率中奖)
* 若中奖 弹出 恭喜你,中奖了
* 若未中奖 弹出 未中奖 再接再厉
Document
测试:
Document
测试:
事先准备一个有内容的txt文本,使用node的fs模块进行读取
// 引入 fs模块
const fs = require('fs');
//调用方法读取文件
fs.readFile('./坏蛋.txt', (err, datda) => {
// 如果失败 抛出错误
if (err) throw '读取失败'
// 如果没有出错 输入内容
console.log(datda.toString())
})
测试:
// 引入 fs模块
const fs = require('fs');
//调用方法读取文件
// fs.readFile('./坏蛋.txt', (err, datda) => {
// // 如果失败 抛出错误
// if (err) throw '读取失败'
// // 如果没有出错 输入内容
// console.log(datda.toString())
// })
//使用promise封装
const p = new Promise((resolve, reject) => {
fs.readFile('./坏蛋.txt', (err, data) => {
//判断如果失败
if (err) reject(err)
//判断若果成功
resolve(data)
})
})
p.then(value => {
console.log('promise读取')
console.log(value.toString())
}, reason => {
console.log('读取失败')
})
测试
再测试读取失败的情况,这里故意把读取文本的位置路径调整为一个错误路径即可
再来试试读取多个文本的传统方式
const fs = require('fs')
fs.readFile('./坏蛋.txt', (err, txt1) => {
fs.readFile('./晴天.txt', (err, txt2) => {
fs.readFile('./七里香.txt', (err, txt3) => {
let result = `
${txt1}
${txt2}
${txt3}`
console.log(result)
})
})
})
测试:
promise方式
const fs = require('fs')
console.log('使用promise实现')
const p = new Promise((resolve, reject) => {
fs.readFile('./晴天.txt', (err, data) => {
resolve(data)
})
})
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./坏蛋.txt', (err, data) => {
resolve([value, data])
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./七里香.txt', (err, data) => {
value.push(data)
resolve(value)
})
})
}).then(value => {
console.log(value.join('\r\n'))
})
测试:
准备一个开放接口
教书先生API - 提供免费接口调用平台
在这个平台里随便找一个开放接口进行测试
Promise封装ajax请求方式
测试
Promise封装ajax请求方式
测试
实例对象中的一个属性 [PromiseState]
pending 未决定的
resolved/fullfilled 成功
rejected 失败
promise只会有pending->resolved或者pending->rejected这两种情况,
不会从resolved->rejected或者rejected->resolv
实例对象中的另一个属性 [PromiseResult]
保存异步任务 [成功/失败]的结果
resolve 成功
reject 失败
Promise构造函数: Promise(executor){}
(1) executor 函数: 执行器(resolve,reject)=>{}
(2) resolve 函数: 内部定义成功时调用的函数 value=>{}
(3) reject 函数: 内部定义失败时调用的函数 reason=>{}
说明: executor会在promise内部立即同步调用 异步操作在执行器中执行
Promise.prototype.then(onRsolved,OnRejected)=>{}:
(1) onResolved 函数 成功的回调函数(value)=>{}
(2) onRejected 函数 失败的回调函数 (reason)=>{}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象
Promise.prototype.catch(onRejected)=>{}
onRejected函数 : 失败的回调函数(reason)=>{}
当promise的状态为失败时会执行的回调函数
Promise.resolve(value)=>{}
value成功的数据或promise对象
说明返回一个成功/失败的promise对象
Document
Promise.reject(reason)=>{}
reason:失败的原因
说明:返回一个失败的promise对象
Promise.all(promises)=>{}
promises:promise数组
说明: 返回一个新的promise 只有所有的promise都成功时才会返回一个成功的promise,只要有一个失败的promise就会直接返回一个失败的promise
数组中所有的promise都成功时返回的结果是一个成功的promise,值是所有成功promise的一个集合
只要有一个失败的promise的话返回的就是一个失败的promise值是第一个失败的promise的结果
可以看到这里举例p1,p3是成功的promise,p2,p4是失败的promise,但是最后打印的结果却是只有p2失败的信息,所以这里只会返回第一个失败的promise,后面失败的promise没有计入到结果集中
可以理解成一旦失败就中断了,后面的promise自然就不用管成功或失败了
Promise.race 方法:(promises)=>{}
promises:n个promise的数组
说明: 返回一个新的promise,数组中第一个完成的promise的结果状态就是最终的结果状态
就如同数组中的promise在赛跑一样,只获取冠军的状态
可以通过调用reslove回调将promise状态更改为成功,调用reject和抛出throw将promise状态修改为rejected
一个promise指定多个成功/失败回调函数时,都会调用吗?
答案:当promise改变为对应的状态时都会调用
多个成功回调
注意这里如果 直接使用链式then写多个失败回调时,只会调用第一个失败回调,其他的调用的是成功回调
解析:
注意:
当 Promise 连续调用 then() 进行回调时,如果第一个 then() 中状态为 rejected,没有返回值默认返回 undefined,那么会进入下一个 then() 的成功回调而不是失败回调,这是因为 Promise 的状态一旦变为 rejected,就会一直保持 rejected 状态,直到有一个错误处理函数(onRejected)被调用,否则会一直向下传递,直到被捕获或者到达 Promise 链的末尾。
因此,当第一个 then() 的状态为 rejected 时,如果没有提供错误处理函数(onRejected),那么下一个 then() 就会被认为是成功回调,因为它是链中的下一个回调函数。如果想要进入下一个 then() 的失败回调,需要在第一个 then() 中提供错误处理函数(onRejected),或者使用 catch() 方法来捕获错误。
改变promise状态和指定回调函数谁先谁后?
(1) 都有可能 正常情况下是先指定回调再改变状态 但也可以先改状态再指定回调
当改变状态的方法是中是同步任务时,就是先改变状态再去执行then的回调函数
但是当改变状态的方法是异步时,就是先执行回调函数再去改变状态
(2) 如何先更改状态再指定回调
在执行器中直接调用 reslove()/reject()
延迟更长时间再调用then()
(3) 什么时候才能得到数据
如果先指定的回调 那么当状态发生改变时 回调函数就会调用 得到数据
如果先改变的状态 那么当指定回调时 回调函数就会调用 得到数据
promise.then() 返回的新promise的结果状态由什么决定
(1) 简单表达: 由then()指定的回调函数执行的结果决定
(2) 详细表达:
如果抛出异常 新的promise变为rejected reason为抛出的异常
如果返回的是非promise的任意值 新promise变为resolved,value为返回的值
如果返回的是另一个新的promise 此promise的结果就会成功新的promise结果
没有返回值和没有抛出异常的情况
result 返回的是一个 Promise 对象,该 Promise 对象是由 p6.then() 返回的。
当调用 p6.then() 时,会返回一个新的 Promise 对象,该对象的状态和值取决于回调函数的执行结果。在这里,回调函数中调用了 console.log() 输出了成功的结果,但是没有返回值,默认返回 undefined,所以该 Promise 对象的状态为 resolved,值为 undefined。
因此,result 返回的是一个状态为 resolved,值为 undefined 的 Promise 对象。
(1) promise的then()返回一个新的promise 可以开成then()的链式调用
(2) 通过then的链式调用串联多个同步/异步任务
注意这里的第一个then的回调返回结果是一个成功的promise对象,所以第二个then回调第一句打印出的就是第一个then的返回的promise的值,而第二个then没有返回值,所以默认undefined,到了第三个then的回调时没有接收到第二个then的返回值,打印undefined
(1) 当使用promise的then链式调用时 可以在最后指定失败的回调
(2) 前面任何操作出了异常 都会传到最后失败的回调中处理
(1) 当使用promise的then链式调用时 在中间中断 不再调用后面的回调函数
(2) 解决办法: 在回调函数中返回一个pendding状态的promise对象
比如这里的then回调,如果只想执行第一个then回调,后面的两个then回调并不想执行,这里只有一个方法,就是在第一个then回调中返回一个pendding状态的promise