promise最大的好处解决地狱回调问题
Promise是es6引入的进行异步编程的新解决方案
Promise是一个构造函数,可以进行对象的实例化
Promise可以用来封装一个异步操作,并且可以获取其成功或者失败的结果值
异步编程
fs文件操作(fs是nodejs下的一个模块,可以对计算机磁盘进行读写操作)
以前:(err,data)=>{}使用的是回调
require('fs').readfile('./index.html',(err,data)=>{})
数据库操作( mangdb ,mysql等数据库操作)
AJAX(网络请求)
data=>{}为一个回调函数
$.get('/server',(data)=>{})
定时器(setTimeout)
setTimeOut(()=>{},2000)
使用Promise的优势
1.支持链式调用,可以解决回调地域问题。
回调地狱:一个回调函数套着另外一个异步任务。缺点:1.不便于阅读2.不便于异常处理
2.指定回调函数的方式会更加灵活
之前必须在执行异步任务之前就得把回调函数准备好
现在有了promise之后:启动异步任务=>返回promise对象=>给promise绑定回调函数(甚至在异步任务之后指定多个回调函数处理成功或者失败的结果)
Promise使用 -fs模块
//fs可以对计算机硬盘进行读写操作
//要求读取resouse文件下面的content.txt
//
//回调函数形式
// //引进fs
const fs = require('fs');
// fs.readFile('./resource/content.txt',(err, data)=>{
// //如果出错,则抛出错误
// if(err) throw err;
// // 没错,输出文件内容
// console.log(data.toString())
// // 终端运行 node Promise练习-fs模块.js
// })
//Promise形式
//创建一个Promise对象
let p =new Promise((resole,reject)=>{
fs.readFile('./resource/content.txt1',(err,data)=>{
//如果出错,抛出
if(err) reject(err);
// 如果成功
resole(data);
})
});
//调用then方法
p.then(value=>{
console.log(value.toString())
},reason => {
console.log(reason)
})
reason就是出错
Promise练习AJAX
把异步代码放进Promise中,成功调用resolve,失败调用reject ,并把成功失败结果传进去,
在then方法中调用成功和失败的回调,对结果进行处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Promise封装AJAX</h2>
<button id="btn">点击发送AJAX</button>
<script>
// 接口地址https://api.apiopen.top/getJoke
//获取元素对象
// const btn = document.querySelector('btn');
//绑定事件
btn.addEventListener('click', function () {
// AJAX四部操作
// 创建Promise
const p = new Promise((resolve, reject) => {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open('GET', 'https://api.apiopen.top/getJoke')
// 3.发送
xhr.send();
// 4.处理响应结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
// 判断响应状态码2XX
if (xhr.status >= 200 && xhr.status < 300) {
// 输出响应体response
// console.log(xhr.response)
resolve(xhr.response)
} else {
// console.log(xhr.status)
reject(xhr.status)
}
}
}
});
p.then(value=>{
console.log(value)
},reason=>{
console.log(reason)
})
})
</script>
</body>
</html>
Promise封装AJAX请求
在别的页面可以使用,在别的页面引入sendAJAX,放置不同的url参数即可
xhr.responseType='json'AJAX设置返回类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 封装一个sendAJAX请求,发送GET AJAX 参数:URL 返回结果:Promise对象
function sendAJAX(url){
return new Promise((resolve,reject)=>{
//1.创建XMLHTTPRequest对象
const xhr = new XMLHttpRequest()
xhr.responseType='json';
//2.初始化模板
xhr.open('GET',url)
//3.发送
xhr.send();
//处理结果onreadystatechange
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
// 判断成功
if(xhr.status>=200&&xhr.status<300){
resolve(xhr.response)
}else{
reject(xhr.status)
}
}
}
})
}
sendAJAX('https://api.apiopen.top/getJoke').then(
value => {
console.log(value)
},
reason => {
console.log(reason)
}
)
</script>
</body>
</html>
Promise封装一个读取函数mineReadFile
//封装一个mineReadFile 参数:path路径 返回:promise对象
function mineReadFile(path){
// 返回结果为promise对象
return new Promise((resolve,reject)=>{
// 功能为读取文件
// readFile第一个参数给path 第二个参数为回调
require('fs').readFile(path,(err,data)=>{
if(err)reject(err)
resolve(data)
})
})
}
mineReadFile('./resource/content.txt')
.then(value=>{
// 输出文件内容
console.log(value.toString())
},reason =>{
console.log(reason)
})
node.js中内置方法promisify
这个方法是 属于util模块的 util.promisify
官方文档:传入一个常见的错误优先的回调风格的函数。
其实是错误优先的回调。在fs中异步的API基本上的回调函数都是err 是第一个参数
会返回一个peomise版本
//util.promisity方法
//引入util模块
const util =require('util')
//引入fs
const fs =require('fs')
let mineReadFile = util.promisify(fs.readFile)
mineReadFile('./resource/content.txt').then(value=>{
console.log(value.toString())
},reason=>{})
Promise的状态改变PromiseState
状态是promise对象中的一个属性,是promise实例对象当中的一个属性 PromiseState
是内置属性,不能进行操作
有三种值:
pending 未决定的
resolved/ fullfilled 成功
rejected 失败
两种可能的变化,只能改变一次
pending变为resolved
pending变为rejected
Promise对象的值PromiseResult
PromiseResult是Promise实例对象的另一个属性
保存着 异步任务 对象成功或者失败的结果
resolve和reject可以修改PromiseResult的值
如何使用Promise
Promise相关的API
Peomise的构造函数:Promise(excutor){}
1.excutor函数:执行器(resolve,reject)=>{ }
2.resolve函数:内部定义成功时调用的函数value=>{}
3.reject函数:内部定义失败时调用的函数reason=>{ }
4.excutor的参数,也就是(resolve,reject)={} 函数的参数是同步调用的,异步操作在执行器中执行
Promise.prototype.then方法(onResolved,onRejected)=>{ }
then方法用来指定回调的,传递两个参数,这些参数都是函数类型的参数
1.onResolved:成功的回调函数value=>{}
2.onRjected:失败的回调函数reason=>{}
Promise.prototype.catch方法(onRejected)=>{}
1.onReject函数:失败时的回调(reason)=>{}
Promise.resolve 方法:value=>{}
1.value:返回一个成功或者失败的promise对象
属于Promise对象,不是实例对象
如果传入参数为非Promise类型的对象,则返回结果为成功promise对象
如果传入的参数为Promise类型的对象,则参数的结果决定resolve的结果
Promise.reject方法:reject=>{}
属于promise这个对象,不属于实例对象
1.reason失败的原因
说明:返回一个失败的peomise对象
Promise.all方法:(promises)=>{ }
1.promises:包含n个promise数组
说明:返回一个新的peomise,只有所有的peomise成功才成功,只要有一个失败就直接失败
成功:
失败:结果为失败的那个值
Promise.race方法:(promises)=>{}
1.promises:包含n个promise对象的数组
说明:返回一个promise,第一个完成peomise的结果状态就是最终的结果
Promise中的几个关键问题
1.如何改变promise的状态
1.调用resolve函数,状态由pending变为resolved/fullfilled
2.调用reject函数,状态由pending变为rejected
3.抛出错误 throw
2.一个promise指定多个成功/失败回调函数,都会调用吗
意思就是then里面的回调,会执行吗?
当promise状态改变之后都会调用,没有调用resolve('ok')的时候都不会调用
3.改变promise状态和指定回调函数谁先谁后
改变状态:resolve,reject,throw
指定回调函数:then,catch
该题可变为:resolve改变状态先执行还是then回调先执行
都有可能
1.改变状态先执行,Promise实列对象是一个同步函数时
2.then指定回调先执行,Promise实例对象中是一个异步函数
异步任务居多
如何先改变状态
1. 在执行器中直接调用resolve/reject
2.异步:给then回调加更长的异步
什么时候能拿到数据?
指的是回调函数then到底什么时候执行
1.先改变状态,立即调用resolve,这时then在调用就会执行回调函数,处理成功或者失败的结果
2.如果是先指定的then回调,后改变状态,这时时改变状态以后,去调用成功或者失败的结果
promise.then()返回的新的promise的结果状态由什么决定
就是result的状态由什么决定
1.答案:是由then指定的回调函数执行结果决定
2.如果抛出异常,新promise变为rejected, reason为抛出的异常
如果返回的是非promise的任意值,新 promise变为resolved, value为返回的值
如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
Promise如何串联多个操作任务
promise 的 then()返回一个新的promise对象,可以开成then()的链式调用
通过then的链式调用串连多个同步/异步任务
第三个console.log的值是由上一个then的返回结果promise决定的,由指定回调函数的返回值决定的,没写返回值就是undefined ,undefined不是一个promise类型的对象,所以返回一个成功的undefined
Promise异常穿透
1.当使用peomise的then方法链式调用时,可以在最后指定失败的回调
用then需要传两个参数,用catch传一个就行
中断Promise链
有且只有一种方式:返回一种pending状态的Promise对象
return new Promise(()=>) 返回为pending 状态没有改变 其他就不会执行
手写Promise----实现之前的API
报错:
p.then会报错 在promise.js中的Promise构造函数上 即显示原型对象上 没有then方法
Promise原型上没有 那么 p实例对象的隐式原型链上就没有then方法
为了能调用then方法,需要添加then方法
resolve函数执行:
1.Promise对应的状态会发生改变由pending变为resolved/fullfilled 状态是实例对象上的一个属性PromiseState ,PromiseState是属于实例对象的
2.设置Promise对象的结果 PromiseResult