在漫漫历史长河中,许多文人墨客对于承诺这个概念有着很多的见解,也留下了很多脍炙人口的篇章,如"君子一言驷马难追",《诗经·邶风·击鼓》中有着一段"死生契阔,与子成说。执子之手,与子偕老。"直至今日依然为世人传颂.
ES6时代,javascript提出了一个新的构造器"promise(承诺)",这掷地有声的名称背后也是前端开发中非常重要的一个语法.
一.什么是promise
promise是ES6提出的一种新语法,一个新的构造器,用于优化实现异步操作。
二.如何使用
1.语法格式
//实例化创建promist对象
let promise = new Promise((resolve, reject) => {
//形参resolve与reject可以改变当前的状态
resolve("我成功了");
// reject('我失败了')
});
//观察promise对象
console.log(promise);
//兑现承诺
promise
.then((res) => {
//当状态PromiseState从pending变化为resolved时触发.即成功
//形参res是resolve承诺的值
console.log(res);
})
.catch((err) => {
//当状态PromiseState从pending变化为rejected时触发.即失败
//形参err是reject承诺的值
console.log(err);
})
.finally(() => {
//不管成功与否,这个函数都会执行
console.log("我都会执行");
});
2.三种状态和值
2.1初始态
pending(待定的,将要发生的),在刚刚创建promise对象时,没有调用resolve或者reject方法,此时的状态(PromiseState)就是pending.
2.2成功态
fulfilled(实现),创建promise对象后,调用了第一个形参'resolve',此时状态就是fulfilled
2.3失败态
rejected(拒绝),在创建promise对象后,调用了第二个形参'reject',此时状态就是rejected
2.4注意点
pending状态可转化,一旦由初始态转化为其他任意一态,转换过程便不可逆了,也就是说转化之后再也不能转化为pending,也不能转化为另一态.
2.5值
调用形参(resolve或reject)时可以传值
2.6兑现
当状态发生变化时,就会调用then()或catch()中,同时将值传入对应的方法的回调函数中.
三.优化异步代码
1.优化ajax
//改写ajax
let getOptimize = () =>
new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(
"get",
"http://www.itcbc.com:3006/api/getbooks?appkey=13200008888"
);
xhr.onload = function () {
resolve(xhr.responseText);
};
xhr.onerror = function () {
reject("请求接口错误");
};
xhr.send();
});
getOptimize()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
2.优化node.js文件的读取
const fs = require("fs");
let getOptimize = (path) =>
new Promise((resolve, reject) => {
fs.readFile(path, "utf8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
getOptimize("3.txt")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
四.then()方法
1.作用
then方法的作用是为Promise对象添加状态改变时的回调函数。
2.then的格式
promise.then(fn1,fn2)//then方法可以写两个参数
第一个参数是fulfilled状态的回调函数,当对象状态是fulfilled时,then()执行第一个函数
第二个参数是rejected状态的回调函数,当对象状态是rejected时,then()执行第二个函数(可选)
如果对象状态为rejected,此时then()方法没有设置第二个参数,那么就会直接抛出一个错误
3.then的返回值
then()方法的返回值是一个全新的promise对象,所以支持链式写法
那么返回出来的新的promise对象的状态是什么?接收的值又在哪里?
p1=new promise(()=>{})
p2 = p1.then(fn1,fn2)
规则:
1.如果p1的状态时pending,那么p2的状态也是pending
2.如果此时p1状态改变为fulfilled,那么then()执行fn1
- 如果fn1返回值不是promise对象,那么p2的状态是fulfilled,p2的值就是fn1函数的return值
- 如果fn1返回值是一个promise对象,那么p2的状态和值由promise对象决定
- 如果fn1函数内部发生了错误,那么p2的状态就是rejected,值就是这个错误对象
3.如果此时p1状态改变为rejected,那么then()执行fn2
- 如果fn2返回值不是promise对象,那么p2的状态是fulfilled,p2的值就是fn2函数的return值
- 如果fn2返回值是一个promise对象,那么p2的状态和值由promise对象决定
- 如果fn2函数内部发生了错误,那么p2的状态就是rejected,值就是这个错误对象
五.catch()方法
1.作用
Promise.prototype.catch 是 Promise.prototype.then(null, reject)的别名,当promise对象的状态为rejected时,调用
let promise = new Promise((resolve,reject)=>{reject('s')})
promise.catch((err)=>{console.log(err)}) === promise.then(null, function(err){console.log(err)})
一般不单独使用catch(),一般与then()一起使用
2.返回值
catch的返回值仍是一个promise对象,确定它的值的方式与then()方法的方式一致。
六.promise的链式调用
function increment(value) {
return value + 1;
}
function doubleUp(value) {
return value * 2;
}
function output(value) {
console.log(value);// => (1 + 1) * 2
}
var p = Promise.resolve(1);//此时promise对象的状态为fulfilled 并传递参数1
p.then(increment)//调用increment函数,传递参数至value,返回2,此时新对象的状态为fulfilled 并传递参数2
.then(doubleUp)//调用doubleUp函数,传递参数至value,返回4,此时新对象的状态为fulfilled 并传递参数4
.then(output)//调用output,传递参数至value,打印输出4
七.async语法
1.什么是async语法
promise升级版,进一步改进异步代码的写法
2.async
添加一个promise对象,可以使用then方法添加回调函数
function f1 () {
return 1
}//普通函数
async function f2 () {
return 1
}//async函数返回1
async function f3 () {}//async函数不返回
//将函数分别赋值
const r1 = f1()
const r2 = f2()
const r3 = f3()
//观察
console.log(r1) // 1
console.log(r2) // Promise, resolved(1)
console.log(r3) // Promise, resolved(undefined)
//then()方法调用
r2.then(res => { console.log(res) })//1
r3.then(res => { console.log(res) })//undefined
3.await命令
await命令后如果是一个promise对象,返回该对象的值.
await命令后如果不是一个promise对象,那么就直接返回该值.
//async函数创建一个函数fn
async function fn() {
//实例化创建一个promise对象
const promise = new Promise((resolve,reject)=>{
//此时对象状态为fulfilled,返回值为undefined
resolve(100)
})
//声明常量a = 1
const a = 1
// await 等待promise的状态变化完成(pending->resolved, pending->rejected)
// 取出promise的值
const b = await promise
//观察
console.log(a,b)//1,100
}
//调用
fn()
4.执行流程
const p1 = new Promise((resolve, reject) => {
setTimeout(()=>resolve(100), 3000)
})
async function f () {
console.log('开始执行f')
var a = await p1
console.log('p1完成了')
console.log(a)
return 1
}
console.log('主函数运行...')
const res = f()
console.log('f()完成,返回值是', res)
res.then(res => { console.log(res) })
5.async的返回值
async 函数返回的 Promise 对象,必须等到内部所有await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve(100), 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve(200), 5000)
})
async function f () {
console.log('开始执行f')
var a = await p1
console.log('p1完成了')
var b = await p2
console.log('p2完成了')
return a + b
}
console.log('主函数运行...')
const res = f()
console.log('f()完成,返回值是', res)
res.then(res => { console.log(res) })
未完待续...