这是我参与「第四届青训营 」笔记创作活动的的第4天
- Promise是JS中用于处理异步编程的新的解决方案(旧的解决方案是回调函数)
异步操作
-
fs文件操作
require('fs').readFile('./index.html',(err,data)=>{}) -
数据库操作
-
AJAX
$.get('/server',(data)=>{}) -
定时器
setTimeout((=>{},2000));
使用Promise的原因
- Promise支持链式调用,可以解决回调地狱问题
- 回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
- 回调地狱导致代码不易阅读,且不方便异常处理
- 使用Promise使得回调函数的方式更加灵活
promise用法
-
流程:启动异步任务=>返回promise对象=>给promise对象绑定回调函数(甚至可以在异步任务结束后指定多个)
-
promise是一个构造函数,函数的参数是一个函数,内部包含异步操作。异步操作执行成功调用resolve方法,异步操作执行失败调用reject方法。resolve和reject方法在then方法中指定。
const p=new Promise((resolve,reject)=>{ setTimeout(()=>{ let p=rand(1,100); if(p<30){ resolve(p);//异步操作执行成功,可把promise状态设置为成功。函数类型的数据 }else{ reject(p);//异步操作执行失败,可把promise状态设置为失败。函数类型的数据 } },1000); }); //成功和失败时的回调,then方法 p.then((value)=>{ alert("恭喜中奖!,您的中奖码为"+value);//异步操作执行成功 },(reason)=>{ alert("未中奖,您的失败码为"+reason);//异步操作执行失败 }) -
用promise封装异步操作FS
const fs=require("fs"); //回调函数形式 // fs.readFile("./test.txt",(err,data)=>{ // if(err) throw err; // console.log(data.toString()); // }); //promise形式。 const p=new Promise((resolve,reject)=>{ fs.readFile("./test.txt",(err,data)=>{ if(err) reject(err); resolve(data.toString()); }) }); p.then((value)=>{ console.log(value); },(reason)=>{ console.log(reason); }) -
用promise封装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){ //判断响应码 if(xhr.status>=200&&xhr.status<300){ //控制台输出响应体 resolve(xhr.response); }else{ //输出状态码 reject(xhr.status); } } } }); p.then((value)=>{ console.log(value); },(reason)=>{ console.log(reason); }); -
使用promise封装读取文件的操作
/** * 函数myReadFile:使用promise方法封装了读取文件的操作 * 参数:文件路径 * 返回值:promise对象 */ function myReadFile(path){ return new Promise((resolve,reject)=>{ require("fs").readFile(path,(err,data)=>{ if(err) reject(err); resolve(data.toString()); }); }) } //这样就将异步操作转换为了同步操作 myReadFile("./test.txt").then((value)=>{ console.log(value); },(reason)=>{ console.log(reason); }); -
借助util的promisfy函数,将异步操作promise化
/** * 借助util的promisfy函数,将异步操作函数promise化 */ const util=require("util"); const fs=require("fs"); const myReadFile=util.promisify(fs.readFile); myReadFile("./test.txt").then((value)=>{ console.log(value.toString()); },(reason)=>{ console.log(reason) });
Promise对象的状态
- pending:未决定的
- resolved:已完成
- rejected:失败
Promise对象的值
- 实例对象中的另一个属性【PromiseResult】,保存着异步任务对象成功/失败的结果
- resolve
- reject
Promise的基本流程
promise构造函数
Promise(executor){}
- executor是构造函数的形参,是一个函数。称为执行器,通常写为(resolve,reject)=>{}
- resolve函数:内部定义成功时调用的函数
- reject函数:内部定义失败时,调用的函数
- 注意:executor中的代码会在Promise内部立即同步执行。异步操作是在resolve中
then方法
promiseObj.then(onResolved,onRejected)
- then方法是处理回调函数,异步操作在这里执行
- onResolved函数:执行成功的回调函数
- onRejected函数:执行失败的回调函数
- 返回一个新的promise对象
catch方法:失败的回调函数
promiseOBJ.catch((reason)=>{})
async函数
- 函数的返回值为promise对象
- promise对象的结果由async函数执行的返回值决定
await函数
-
await右边的表达式为promise对象
-
如果右边的表达式为promise对象,await返回的是promise成功的值
-
await必须写在async函数中。但async函数中可以没有await。
-
如果await的promise失败了,就会抛出异常,通过try....catch捕获处理
async function main(){
let p=new Promise((resolve,reject)=>{
reject('error');
});
//p成功时
let res=await p;
//p失败时
try{
let res=await p;
}catch(e){
console.log(e);
}
}
async和await函数的结合使用
- await必须放在async函数中
const util=require('util');
const fs=require('fs');
const myReadFile=util.promisify(fs.readFile);
async function my(){
let d1=await myReadFile('./test.txt');
let d2=await myReadFile('./test02.txt');
console.log(d1+d2);
}
my();