Promise使用

Promise

Promise 是异步编程的一种解决方案,可以简化代码、支持链式调用,解决回调地狱

异步任务有哪些

  • 定时器
  • 数据库操作
  • Ajax请求
  • fs文件操作

Promise基本使用

const but=document.getElementById("but")
but.addEventListener("click",function (){
    let randomNumber=Math.ceil(Math.random()*100)
    // 创建 promise 实例
       const p = new Promise(function (resolve, reject){
           setTimeout(()=>{
               if(randomNumber<30){
               //成功的状态
               resolve(n);
           }else{
               //失败的的状态
               reject(n);
           }
           },1000)
       })
       // 这里用then函数执行成功或者失败的回调
       // 参数需要两个回调,第一个为成功的回调,第二个为失败的回调
        p.then(value => {
            alert('恭喜,您中奖了' + value);
        },reason => {
            alert('很遗憾,您没有中奖' + reason);
        })
})

Promisify()

promisify()util封装好的工具,可将传入参数变为promise风格

// 将fs模块promise化流程

// 1、引入所需要的模块
const util = require('util');
const fs = require('fs');

// 2、将fs.readFile变成promise风格
const promiseFS = util.promisify(fs.readFile);

// 3、正常使用
promiseFS('text').then(value => {
    console.log(value);
}, () => {
	console.log('error');  
})

Promise的流程

promiseState
  • 状态值

    • pending 未决定的

    • resolve / fullfilled 成功

    • rejected 失败

  • Promise 状态改变

    • pending 变为 resolved
    • pending 变为 rejected
promiseResult
  • 保存异步任务成功 / 失败的结果
  • 只能由resolve、reject来修改
流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGx6hqcq-1682324391955)(D:\Typora\photos\image-20221108164221889.png)]

API

构造函数

函数在Promise内部立即同步调用执行

const p = new Promise((resolve, reject) => {
	console.log(111);
})
console.log(222);
// 111
// 222
then方法
p.then(resolve(){
       
}, reject(){
    
})
catch方法
  • 指定失败的回调
p.catch(reson => {
    console.log(reason);
})
resolve方法
  • 将一个元素转换成一个成功 / 失败的promise对象,成功 / 失败取决于传入参数
let p1 = Promise.resolve(521);
console.log(p1) // promise对象

let p2 = Promise.resolve(
    new Promise((resolve, reject) => {
        // resolve('OK');
        reject("Error");
    })
);
// 如果不对出错进行处理(指定错误回调),控制台就会报错
p2.then(value => {
	console.log(value);
},reason => {
    // Error
	console.log(reason);
});
console.log(p2)
reject方法
  • 将传入的参数转换成失败的promise对象(promiseState为rejected)
let p1 = Promise.reject(521);
let p2 = Promise.reject('haha');
// 即便传入成功的,得到的promise对象状态也是失败的
let p3 = Promise.reject(
	new Promise((resolve, reject) => {
		resolve("OK");
	})
);

p3.then((value) => {
	console.log(value);
},(reason) => {
	console.log(reason);
});

console.log(p1);
console.log(p2);
console.log(p3);
all方法
  • 传入一个promise的数组,返回一个新的promise
  • 其promiseState为传入数组中的promise对象状态逻辑与结果(全为成功才是成功,一个失败全失败)
  • 其promiseResult结果为成功,则promiseResult的结果为传入数组各promiseResult的结果组成的数组,若失败,promiseResult的结果为第一个失败的对象中promiseResult值
let p1 = new Promise((resolve, reject) => {
	resolve("OK");
});
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve("Oh Yeah");
var result = Promise.all([p1, p2, p3]);

console.log(result);
/*
Promise
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(3)
0: "OK"
1: "Success"
2: "Oh Yeah"
length: 3
[[Prototype]]: Array(0) */


let p4 = Promise.reject("Error");
var result = Promise.all([p1, p2, p4]);

console.log(result);
/*
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "Error */
race方法
  • 第一个完成的promise的状态和结果值就是最终生成的promise对象的状态和结果值
let p1 = new Promise((resolve, reject) => {
  	setTimeout(() => {
    	reject("OK");
  	}, 1000);
});
let p2 = Promise.resolve("Error");
let p3 = Promise.resolve("Oh Yeah");

const result = Promise.race([p1, p2, p3]);
console.log(result);  // p2

几个关键问题

如何改变 Promise 的状态
let p = new Promise((resolve, reject) => {
	// 1. resolve 函数
	resolve("ok"); // pending   => fulfilled (resolved)
	// 2. reject 函数
	reject("error"); // pending  =>  rejected
	// 3. 抛出错误
	throw "出问题了";
});
指定多个回调函数,是否都会被调用
let p = new Promise((resolve, reject) => {
    //如果注释掉resolve(),那么p的状态就还是pending,即状态未发生改变,不会调用then
	resolve("OK"); 
});

// 绑定的这两个回调,只要状态发生了改变就都会被同时调用
p.then((value) => {
	console.log(value);
});

p.then((value) => {
	console.log(value);
});
改变状态和then函数执行先后
  • 谁先谁后都是有可能的,在一般情况下(回调函数内是一个同步任务,直接调用resolve或者reject时)先改变状态再执行then函数,若回调函数内是一个异步任务,则会先执行then函数再改变状态
  • 什么时候才能得到数据?
    • 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    • 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
Promise .then()返回的新 Promise 的结果状态由什么决定
  • then() 会返回一个新的promise

  • 其状态值和结果值由then()指定的回调函数执行结果决定

    • 若抛出异常,新promise则为失败,reason为结果值
    • 若返回的是非promise的任意值,新promise值会变成成功,value为返回值
    • 若返回的是另一个新的promise,该promise的结果是新的promise的结果(是成功新的也为成功,是失败新的也会是失败)
    • 若什么回调函数都不返回,其新promise状态值为fullfilled,结果值为undefined
let p = new Promise((resolve, reject) => {
	resolve("ok");
	// reject("no");
});
//执行 then 方法
let result = p.then((value) => {
	// console.log(value);
	//1. 抛出错误 rejected
	// throw "出了问题";
   	//2. 返回结果是非 Promise 类型的对象 fulfilled
   	// return 521;
   	//3. 返回结果是 Promise 对象 fulfilled/rejected
   	return new Promise((resolve, reject) => {
     	// resolve("success");
     	reject("error");
   	});
},(reason) => {
   	console.warn(reason);
})
console.log(result);
Promise 如何串连多个操作任务?
  • 由于Promise的 then()返回一个新的 Promise,因此可以通过 then 的链式调用串连多个同步/异步任务
let p = new Promise((resolve, reject) => {
   	setTimeout(() => {
       	resolve('OK');
   	}, 1000);
});	
p.then(value => {
   	return new Promise((resolve, reject) => {
       	resolve("success");
   	});
}).then(value => {
   	console.log(value);  // success
}).then(value => {
    // 这里是打印的是结果值,then函数还是会返回一个promise类型
   	console.log(value);  // undefined
})
Promise 异常传透
  • 当使用 Promise 的 then 链式调用时,可以在最后指定失败的回调
  • 中间任何操作抛出了异常,都会传到最后失败的回调中处理,且出现异常之后的回调都不会再执行
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 => { //用then也可以捕获异常,不过then要传两个参数
    console.warn(reason);
});
console.log(p)
如何中断 Promise 链
  • 处于pending状态时,状态并未发生改变,then()的回调函数不会被执行,可以在回调函数中返回一个 pendding 状态的 Promise 对象中中断promise链
let p = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('OK');
    }, 1000);
});
let a = p.then(value => {
    console.log(111);
    // 中断promise链
    return new Promise(() => {});
}).then(value => {
    console.log(222);
}).then(value => {
    console.log(333);
}).catch(reason => {
    console.warn(reason);
});

async函数

  • 返回值为promise对象
  • promise对象的结果由async函数执行的返回值决定(和 then() 规则一样)
    • 返回值是一个非promise对象,其状态值为fullfilled,其结果值为return的值
    • 返回值如果是一个promise对象,函数返回值则为该对象
    • 返回值抛出异常,函数返回状态值为reject,结果值为异常
async function main() {
//1. 如果返回值是一个非Promise类型的数据 则状态为成功,返回一个成功的promise对象
 	return 521;
}
async function main1() {
//2. 如果返回的是一个Promise对象 则状态取决于返回结果
 	return new Promise((resolve, reject) => {
   	// resolve('OK'); //成功
   	reject("Error"); //失败
 	});
}
async function main2() {
// 3. 抛出异常 返回一个失败的promise对象
 	throw "Oh NO";
}
let result = main();
let result1 = main1();
let result3 = main2();
console.log(result);
console.log(result1);
console.log(result3);

await关键字

  • 获取状态为成功时的结果值

    • 如果是promise对象且状态为成功,返回其成功时的结果值,
    • 如果是promise对象状态为失败,抛出错误,且需要通过 try…catch 捕获处理
    • 如果是非promise对象,返回关键字后面的值
  • await 必须写在 async 函数中, 但 async 函数中可以没有 await

async function main() {
	let p = new Promise((resolve, reject) => {
		resolve("OK");
		// reject("Error");
  	});
	//1. 右侧为promise的情况
	let res = await p;
    console.log(res); // ok
	//2. 右侧为其他类型的数据
	let res2 = await 20;
    console.log(res); // 20
	//3. 如果promise是失败的状态
  	try {
		let res3 = await p;
		console.log(res3)
  	} catch (e) {
		//catch捕获失败状态
		console.log(e);  // Error
	}
}

async函数和await关键字的综合应用

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);

async function test(){
    try{
        let data1 = await readFile('./data1.txt');
        let data2 = await readFile('./data2.txt');
        let data3 = await readFile('./data3.txt');
        
        console.log(data1 + data2 + data3);
    }catch(e){
        console.log(e);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值