目录
(1)抽象表达:
1) Promise 是一门]新的技术(ES6规范)
2) Promise 是JS中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
(2)具体表达:
1)从语法上来说: Promise是一个构造函数
2)从功能上来说:promise对象用来封装-一个异步操作并可以获取其成功/失败的结果值
优点:
(1)指定回调函数的方式更加灵活
旧的: 必须在启动异步任务前指定
promise: 启动异步任务=>返回promie对象=>给promise对象绑定回调函数(甚至可以在 异步任务结束后指定/多个)
(2)支持链式调用,可以解决回调地狱问题扩展:
回调地狱定义:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
回调地狱的缺点:不便于阅读、不便于异常处理
(1)Promise构造函数
Promise(executor){ }
其中executor函数为执行器:{resolve,reject)=>{},它会在Promise内部立即同步调用,异步操作在执行器中执行
let p = new Promise((resolve, reject) => { //同步调用 console . log(111); }); console. log(222);(2)Promise.prototype.then 方法: (onResolved, onRejected)=> {}
1) onResolved 函数:成功的回调函数(value) => {}
2) onRejected. 函数:失败的回调函数(reason)=> {}
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象
(3) Promise.prototype.catch 方法: (onRejected)=> {}
onRejected 函数:失败的回调函数(reason) => {}
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>title>
- <style>
- #btn{
- width:50px;
- height:50px;
- background-color: aqua;
- }
- style>
- head>
- <body>
- <div class="container">
- <h2 class="page-header">Promise 初体验h2>
- <button class="btn btn-primary" id="btn">点击抽奖button>
- div>
- <script>
- //生成随机数
- function rand(m,n){
- return Math.ceil(Math.random()*(n-m+1))+m-1;
- }
- /**
- 点击按钮,1s后显示是否中奖(30%概率中奖)
- 若中奖弹出 恭喜恭喜,奖品为10万
- 若未中奖弹出 再接再厉
- */
- const btn=document.querySelector('#btn');
- //绑定单击事件
- btn.addEventListener('click',function(){
- /* //定时器
- setTimeout(()=>{
- let n=rand(1,100);
- if(n<=30){
- alert('恭喜恭喜,奖品为10万')
- }else{
- alert('再接再厉')
- }
- },1000)*/
- //Promise形式实现
- // resolve 解决函数类型的数据
- // reject 拒绝函数类型的数据
- const p = new Promise((resolve, reject) => {
- setTimeout(() => {
- let n = rand(1, 100);
- //判断
- if(n <= 30){
- resolve(n); //将promise对象的状态设置为「 成功」
- }else{
- reject(n); //将promise 对象的状态设置为「失败」
- }
- }, 1000);
- });
- //调用then 方法
- p.then((value) => {
- alert('恭喜恭喜,奖品为10万,您的中奖数字为'+value);
- },(reason)=>{
- alert('再接再厉,您的号码为'+reason);
- });
-
- })
-
- script>
- body>
- html>
- /**
- 封装一个函数ReadFile读取文件内容
- *参数:
- path文件路径
- 返回:
- promise对象
- */
- function ReadFile(path){
- return new Promise((resolve,reject)=>{
- //读取文件
- require('fs').readFile(path,(err,data)=>{
- if(err)reject(err);
- resolve(data);
- })
- })
- }
- ReadFile('./resource/content.txt')
- .then(value=>{
- console.log(value.toString());
- },reason=>{
- console.log(reason);
- })
util.promisify(original)函数
- //引入util 模块
- const util = require( 'util' );
- //引入fs模块
- const fs = require('fs');
- //util.promisify方法将返回一个新的函数由原来的回调函数风格转化为Promise风格的函数
- let ReadFile = util.promisify(fs.readFile);
- ReadFile('./resource/ content.txt').then(value=>{
- console.log(value.toString());
- },reason=>{
- console.log(reason)
- });
-
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Promise封装AJAX请求title>
- head>
- <body>
- <script>
- /**
- 封装一个函数sendAJAX 发送GET AJAX请求
- 参数 URL
- 返回结果Promise 对象*/
- 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://127.0.0.1:8000/server')
- .then(value=>{
- console.log(value)
- },reason=>{
- console.log(reason)
- })
- script>
- body>
- html>
服务器.js
- const express=require('express')
- const app=express();
- app.all('/server',(request,response)=>{
- //设置响应头 (此处设置允许跨域)
- response.setHeader('Access-Control-Allow-Origin','*');
- //响应头
- response.setHeader('Access-Control-Allow-Headers','*');
- //设置响应体(响应体一定是字符串)
- const data={name:'zhangSan'};
- //JSON.stringify( {} , [ ] , ""),把数据序列化为json字符串
- let str=JSON.stringify(data);
- response.send(str);
-
- })
- app.listen(8000,()=>{
- console.log('服务器已经启动,8000端口监听中')
- })
1)Promise 的状态-----实例对象中的一个属性(PromiseState)
pending 未决定的
resolved / fullfilled 成功
rejected 失败
2)状态改变
1. pending 变为resolved
2. pending 变为rejected只有这2种,且一个promise对象只能改变一次
实例对象中的另一个属性「PromiseResult」
保存着异步任务成功/失败的结果:resolve/reject
(1)Promise.resolve方法:(value)=>{}
value: 成功的数据或promise对象
说明:返回一个成功/失败的promise对象
-
- let p1 = Promise. resolve(521);
- //如果传入的参数为非Promise 类型的对象,则返回的结果为成功promise对象
- //如果传入的参数为Promise 对象,则参数的结果决定了resolve 的结果
- let p2 = Promise . resolve(new Promise((resolve, reject) => {
- // resolve('OK');
- reject( ' Error');
- }))
- // console .1og(p2);
- //处理失败的结果
- p2.catch(reason => {
- console . log(reason);|
- })
(2)Promise.reject方法:(reason)=>{}
reason:失败的原因
无论传入参数为什么, 永远返回一个失败的promise对象
(3)Promise.all:(promise)=>{}
promises:包含n个promise的数组
说明:返回一个新的promise,只有所有的promise都成功才成功,成功的结果是所有成功的结果组成的数组;只要有一个失败了就直接失败,失败的结果是数组中失败的结果
(4)Promise.race方法:(promises)=>{}
promises:包含n个promise的数组
说明:返回一个新的promise,第一个改变的promise的结果状态就是最终的结果状态
(1)如何改变 promise的状态?
1) resolve(value): 如果当前是pending就会变为resolved
2) reject(reason): 如果当前是pending就会变为rejected
3)抛出异常:如果当前是pending就会变为rejected
(2)一个promise指定多个成功/失败回调函数(即then方法绑定多个回调),都会调用吗?
当promise改变为对应状态时都会调用
(3)改变promise状态和指定回调函数谁先谁后?
都有可能,当执行器函数中的任务是同步任务时,直接去调用时就是改变promise状态先执行; 当执行器函数中的任务是异步任务时,then方法先执行,改变promise状态后执行。
如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject()
②延迟更长时间才调用then()
什么时候才能得到数据(回调函数什么时候执行)?
①如果先指定的回调, 那当状态发生改变时,回调函数就会调用,得到数据
②如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
(4)promise.then()返回的新promise的结果状态由什么决定?
1)简单表达: 由then()指定的回调函数执行的结果决定
2)详细表达:
①如果抛出异常, 新promise变为rejected, reason为抛出的异常
②如果返回的是非promise的任意值,新promise变为resolved, value为返回的值
③如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
(5)promise如何串联多个操作任务?
1) promise 的then()返回一个新的promise, 可以开成then()的链式调用
2)通过then的链式调用串连多个同步/异步任务
-
- let p = new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve('OK');
- }, 1000);
- });
- p. then(value => {
- return new Promise((resolve, reject) => {
- resolve("success" );
- });
- }).then(value => {
- console.1og(value);//success
- }). then(value => {
- console.log(value);//undefined
- })
(6)promise异常传透?
1)当使用promise的then链式调用时,可以在最后指定失败的回调,
2)前面任何操作出了 异常,都会传到最后失败的回调中处理
- let p = new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve('OK');
- //reject('Err');
- },
- 1000);
- });
- p. then(value => {
- // console. log(111);
- throw '失败啦!';
- }). then(value => {
- console . log(222);
- }).then(value => {
- console . log(333);
- }). catch(reason => {
- console.warn(reason); //失败啦!
- });
(7)如何中断promise链?
1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
2)办法: 在回调函数中返回一个pendding状态的promise对象
- let p = new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve( 'OK' );
- }, 1000);
- });
- p. then(value => {
- console.log(111);
- //有且只有一个方式
- return new Promise(() => {});
- }). then(value*=>-{
- console.1og(222) ;
- }) . then(value => {
- console. log(333);
- }). catch(reason => {
- console.warn( reason);
- });
六 Promise封装
- class Promise{
-
- //构造方法
- constructor(executor){
- //添加属性
- this.PromiseState='pending';
- this.PromiseResult=null;
- this.callbacks=[]
- //保存实例对象的this值
- const self=this;
- //resolve函数
- function resolve(data){
- //判断状态
- if(self.PromiseState!=='pending')return;
- //1.修改对象的状态(PromiseState)
- self.PromiseState='fulfilled';
- //2.设置对象结果值(promiseResult)
- self.PromiseResult=data;
- setTimeout(()=>{
- //调用成功的回调函数
- self.callbacks.forEach(item=>{
- item.onResolved(data);
- })
- })
- }
- //reject函数
- function reject(data){
- //判断状态
- if(self.PromiseState!=='pending')return;
- //1. 修改对象的状态( promiseState)
- self.PromiseState = 'rejected' ;//
- //2. 设置对象结果值( promiseResult)
- self.PromiseResult = data;
- //调用失败的回调函数
- setTimeout(()=>{
- self.callbacks.forEach(item=>{
- item.onRejected(data);
- })
- })
- }
- try{
- //同步调用
- executor(resolve,reject);
- }catch(e){
- reject(e);
- }
- }
- //then方法封装
- then(onResolved, onRejected){
- const self=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(self.PromiseResult)
- //判断
- if(result instanceof Promise){
- result.then(v=>{
- resolve(v)
- },r=>{
- reject(r)
- })
- }else{
- //结果对象状态为成功
- resolve(result)
- }
- }catch(e){
- reject(e)
- }
- }
- //调用回调函数 PromiseState
- if(this.PromiseState==='fulfilled'){
- setTimeout(()=>{
- callback(onResolved)
- })
- }
- if(this.PromiseState==='rejected'){
- setTimeout(()=>{
- callback(onRejected)
- })
- }
- //判断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){
- return new Promise((resolve,reject)=>{
- if(value instanceof Promise){
- value.then(v=>{
- resolve(v)
- },r=>{
- reject(r)
- })
- }else{
- //状态设置成功
- resolve(value);
- }
- })
- }
- //添加reject方法
- static reject(value){
- return new Promise((resolve,reject)=>{
- reject(reason);
- })
- }
- //添加all方法
- static all(promises){
- let count=0;
- let arr=[];
- for(let i=0;i
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
length;i++){ - promises[i].then(v=>{
- //修改返回对象的状态为成功
- resolve(v);
- },r=>{
- //修改返回对象的状态为失败
- reject(r);
- })
- }
- })
- }
- }
async函数:async function 函数名(){ }
函数的返回值为promise对象
promise对象的结果由async函数执行的返回值决定
await表达式指定异步执行的任务:
await右侧的表达式一般为promise对象,但也可以是其它的值
如果表达式是promise对象, await返回的是promise成功的值
如果表达式是其它值,直接将此值作为await的返回值
注意:
await必须写在async函数中,但async函数中可以没有await
如果await的promise失败了,就会抛出异常,需要通过t..catch捕获处理
读取文件:
- const fs=require('fs')
- const util=require('util');
- const mineReadFile=util.promisify(fs.readFile)
- /*
- //回调函数的方式
- fs. readFile('../resource/content.txt', (err, data1) => {
- if(err) throw err;
- fs. readFile('../resource/content2.txt', (err, data2) => {
- if(err) throw err;
- console.log(data1 + data2 );
- });
- });
- */
- //async与await
- async function main(){
- try{
- let data1=await mineReadFile('../resource/content.txt');
- let data2=await mineReadFile('../resource/content2.txt');
- console.log(data1+data2)
- }
- catch(e){
- console.log(e)
- }
- }
- main();