一、什么是Promise
Promise
是ES6中的一个内置对象,实际是一个构造函数,是JS中进行异步编程的新的解决方案。
特点:
- ① 三种状态:
pending
(进行中)、resolved
(已完成)、rejected
(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都不能改变这个状态。 - ② 两种状态的转化:其一,从
pending
(进行中)到resolved
(已完成)。其二,从pending
(进行中)到rejected
(已失败)。只有这两种形式的转变。 - ③
Promise
构造函数的原型对象上,有then
()和catch
()等方法,then
()第一个参数接收resolved()
传来的数据,catch()
第一个参数接收rejected()
传来的数据。
作用:
- ① 通常用来解决异步调用问题
- ② 解决多层回调嵌套的方案
- ③ 提高代码可读性、更便于维护
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('要返回的数据');
}, 2000);
});
p.then(data => {
console.log(data);
console.log('这是成功操作');
});
p.catch(error => {
console.log(error);
console.log('这是失败操作');
})
流程如下:
二 、Promise几种常用方法
1.Promise.all()
将多个Promise封装成一个新的Promise,成功时返回的是一个结果数组,失败时,返回的是最先rejected状态的值。
使用场景:一次发送多个请求并根据请求顺序获取和使用数据
// Promise.all调用
Promise.all([
Promise.resolve("直接返回成功"),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
message: "第一个请求结果",
})
},1000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
message: "第二个请求结果",
})
},1000)
}),
]).then(results => {
// 三个promise都是成功的,所以会输出一个数组
console.log("调用结果数组results:", results);
console.log("调用结果一起处理操作...");
}).catch(error => {
console.log("Promise.all调用错误!!", error);
});
// 上面的也可以拆分写为:
let promise1 = Promise.resolve("直接返回成功");
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
message: "第一个请求结果",
});
}, 1000);
});
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
message: "第二个请求结果",
});
}, 1000);
});
let promise4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("直接返回失败1");
}, 1000);
});
let promise5 = Promise.reject("直接返回失败2");
Promise.all([promise1, promise2, promise3])
.then((results) => {
//三个promise都是成功的,所以会输出一个数组
console.log("调用结果数组results:", results);
console.log("调用结果一起处理操作...");
})
//若是里面有一个失败的,则:直接返回promise4的失败结果
Promise.all([promise1, promise2, promise3, promise4])
.then((results) => {
console.log(results)
}).catch((error) => {
//promise4是失败的,所以只会返回promise4的失败结果
console.log(error) //promise4
})
Promise.all([promise1, promise2, promise3, promise4, promise5]).then((results) => {
console.log(results)
}, (error) => {
//promise4个promise5都是失败的,但是promise5比promise4最先失败,所以返回promise5的失败结果
console.log(error) //promise5
})
三、Promise的链式调用
我们可以用 promise.then()
,promise.catch()
和 promise.finally()
这些方法将进一步的操作与一个变为已敲定状态的 promise
关联起来。这些方法还会返回一个新生成的promise
对象,这个对象可以被非强制性的用来做链式调用
// 1,Promise原始链式调用
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("请求结果:", 1);
resolve(1);
}, 1000)
}).then(data => {
console.log("第一次对结果处理");
return new Promise((resolve, reject) => {
resolve(data * 2);
});
}).then(data => {
console.log("第二次对结果处理");
return new Promise((resolve, reject) => {
resolve(data * 3);
});
}).then(data => {
console.log("第三次对结果处理");
data *= 4;
console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
console.log("链式调用中某个环节出现错误!!", err);
})
// 2,Promise的链式简化写法
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("请求结果:", 1);
resolve(1);
}, 1000)
}).then(data => {
console.log("第一次对结果处理");
return Promise.resolve(data * 2);
}).then(data => {
console.log("第二次对结果处理");
return Promise.resolve(data * 3);
}).then(data => {
console.log("第三次对结果处理");
data *= 4;
console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
console.log("链式调用中某个环节出现错误!!", err);
})
// 3,Promise的链式最简化写法
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("请求结果:", 1);
resolve(1);
}, 1000)
}).then(data => {
console.log("第一次对结果处理");
return data * 2
}).then(data => {
console.log("第二次对结果处理");
return data * 3
}).then(data => {
console.log("第三次对结果处理");
data *= 4;
console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
console.log("链式调用中某个环节出现错误!!", err);
})
四、什么是Async/Await
什么是Async/Await
async
、await
是Generator
函数的语法糖,原理是通过Generator
函数加自动执行器来实现的,这就使得async
、await
跟普通函数一样了,不用再一直next
执行了。
他吸收了Generator
函数的优点,可以通过await
来把函数分状态执行,但是又不用一直next
,可以自动执行。
var fs = require('fs');
var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) reject(error);
resolve(data);
});
});
};
var gen = function* (){
var f1 = yield readFile('/usr/web');
var f2 = yield readFile('/usr/ngnix');
console.log(f1.toString());
console.log(f2.toString());
};
写成 async
函数,就是下面这样。
var asyncReadFile = async function (){
var f1 = await readFile('/usr/web');
var f2 = await readFile('/usr/ngnix');
console.log(f1.toString());
console.log(f2.toString());
};
比较发现,async
函数就是将 Generator
函数的星号(*)替换成 async
,将 yield
替换成 await
,仅此而已。
参考来源:async 函数的含义和用法
Async/Await的特点
① async/await是ES8新特性
② async/await是写异步代码的新方式,以前的方法有回调函数和Promise
③ async/await是Generator函数的语法糖,原理是通过Generator函数加自动执行器来实现的
④ async/await与Promise一样,是非阻塞的
⑤ async/await使得异步代码看起来像同步代码,这正是它的魔力所在
async
函数一定会返回一个promise
对象。如果一个async
函数的返回值看起来不是promise
,那么它将会被隐式地包装在一个promise
中。
例如:
async function foo() {
return 1
}
// 等价于:
function foo() {
return Promise.resolve(1)
}
async
函数的函数体可以被看作是由 0 个或者多个 await
表达式分割开来的。从第一行代码直到(并包括)第一个 await
表达式(如果有的话)都是同步运行的。这样的话,一个不含 await
表达式的 async
函数是会同步运行的。然而,如果函数体内有一个 await
表达式,async
函数就一定会异步执行。
async function foo() {
await 1
}
// 等价于:
function foo() {
return Promise.resolve(1).then(() => undefined)
}
参考来源:async 函数
五、Promise和async await区别
Async/await 比 Promise 更优越的表现
1、简洁干净:使用 async/await 能省去写多少行代码
2、错误处理:async/wait 能用相同的结构和好用的经典 try/catch 处理同步和异步错误,错误堆栈能指出包含错误的函数。
3、调试:async/await 的一个极大优势是它更容易调试,使用 async/await 则无需过多箭头函数,并且能像正常的同步调用一样直接跨过 await 调用。
Async/await进一步优化了Promise.then()的缺点,使代码更简洁,所以在项目中尽量使用Async/await