回调函数
获取异步操作的结果
不成立情况
function add(x,y) {
console.log(1)
setTimeout(() => {
console.log(2)
var ret = x + y
return ret
}, 1000);
console.log(3)
//到这里执行结束 不会等待定时器
}
console.log(add(10,20))
结果
1
3
undfine
2
回调函数
function add(x,y,callback) {
//callback就是回调函数
//var callback = function(ret){console.log(ret)}
console.log(1)
setTimeout(() => {
console.log(2)
var ret = x + y
callback(ret)
}, 1000);
}
add(10,20,function (ret) {
console.log(ret)
})
Promise
无法决定输出顺序 (异步)
回调地狱:
异步代码:无法决定输出顺序
eg:
输出结果:
决定输出顺序
回调地狱
套娃
const fs = require('fs')
fs.readFile('./data/a.txt','utf8',function (err,data) {
if(err){
// return console.log('err')
// 抛出异常
// 1.阻止程序执行
// 2.把错误消息打印打控制台
throw err
}
console.log(data)
fs.readFile('./data/b.txt','utf8',function (err,data) {
if(err){
// return console.log('err')
// 抛出异常
// 1.阻止程序执行
// 2.把错误消息打印打控制台
throw err
}
console.log(data)
fs.readFile('./data/c.txt','utf8',function (err,data) {
if(err){
// return console.log('err')
// 抛出异常
// 1.阻止程序执行
// 2.把错误消息打印打控制台
throw err
}
console.log(data)
})
})
})
结果 顺序正确
Promise解决回调地狱
理解
小例子
var fs = require('fs')
//ES6 promise
//1 创建一个Promise 容器
console.log(1)
new Promise(function () {
console.log(2)
fs.readFile('./data/a.txt','utf8',function (err,data) {
if(err){
//失败了
}else{
//成功了
console.log(3)
}
})
})
console.log(4)
//输出结果
1 2 4 3
先1 到promise 2
再4 最后promise结束 3
正式使用
基本语法
var p1 = new Promise(function (resolve,reject) {
fs.readFile('./data/a.txt','utf8',function (err,data) {
if(err){
//失败了
reject(err)
}else{
//成功了
resolve(data)
}
})
})
//then 中的data 就是 resolve(data)的data
//catch 中的err 就是 reject(err)err
p1.then((data)=>{
console.log(data)
}).catch((err)=>{
console.log('失败',err)
})
实现效果
var fs = require('fs')
//ES6 promise
//1 创建一个Promise 容器
var p1 = new Promise(function (resolve,reject) {
fs.readFile('./data/a.txt','utf8',function (err,data) {
if(err){
//失败了
reject(err)
}else{
//成功了
resolve(data)
}
})
})
var p2 = new Promise(function (resolve,reject) {
fs.readFile('./data/b.txt','utf8',function (err,data) {
if(err){
//失败了
reject(err)
}else{
//成功了
resolve(data)
}
})
})
var p3 = new Promise(function (resolve,reject) {
fs.readFile('./data/c.txt','utf8',function (err,data) {
if(err){
//失败了
reject(err)
}else{
//成功了
resolve(data)
}
})
})
//then 中的data 就是 resolve(data)的data
//catch 中的err 就是 reject(err)err
p1.then((data)=>{
console.log(data,'p1')
//当 p1 读取成功的时候
//当前函数中return 的结果就可以在后面的then 中 function 接收到
//当你 return 123 后面就能接收到 123
// return 'hello' 后面就接收到 'hello'
// 没有 return 后面收到的就是 undefined
//上面那些return的数据没什么用
//真正有用的是:我们可以 return 一个 Promise
//当return 一个 Promise 对象的时候,后续的then中的方法 的第一个参赛会作为 p2的 resolve
return p2
}).catch((err)=>{
console.log('失败',err)
})
.then((data)=>{
console.log(data,'p2')
return p3
})
.then((data)=>{
console.log(data,'p3')
})
封装promise API
封装
function pReadFile(filrPath) {
return new Promise(function (resolve,reject) {
fs.readFile(filrPath,'utf8',function (err,data) {
if(err){
//失败了
reject(err)
}else{
//成功了
resolve(data)
}
})
})
}
使用
pReadFile('./data/a.txt')
.then((data)=>{
console.log(data,'p1')
return pReadFile('./data/b.txt')
})
.then((data)=>{
console.log(data,'p2')
return pReadFile('./data/c.txt')
})
.then((data)=>{
console.log(data,'p3')
})
结果
Promise使用场景
应用场景
get('data.json',function (data1) {
console.log(data)
get('data22.json',function (data2) {
console.log(data2)
})
})
Promise
var data = {}
return new Promise(()=>{
get('data.json')
})
.then((data1)=>{
data.user = data1
return new Promise(()=>{
get('data22.json')
})
})
.then((data2)=>{
data.jobs = data2
})
axios 使用Promise场景
先封装
export default {
fetchData (url, methods, datas) {
return new Promise((resolve, reject) => {
axios({
url: url,
method: methods,
data: datas
}).then((res) => {
resolve(res)
}).catch(function (error) {
reject(error)
// console.log(error);
})
})
}
}
module.exports = api
使用
getData () {
api.fetchData('https://www.apiopen.top/novelApi','get')
.then(res=>{
console.log(res.data,'111');
return api.fetchData('https://www.apiopen.top/novelApi','get')
},error => {
console.log(error)
})
.then(res=>{
console.log(res.data,'222');
return api.fetchData('https://www.apiopen.top/novelApi','get')
},error => {
console.log(error)
})
}
async和await
async
async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行。
使用:
async function timeout() {
return 'hello world';
}
console.log(timeout());
输出结果:调用会返回一个promise 对象。
通过.then输出结果
异步函数:
async function timeout() {
return 'hello world'
}
timeout().then(result => {
console.log(result);
})
console.log('虽然在后面,但是我先执行');
结果:
await (等待)
await 关键字只能放到async 函数里面
现在写一个函数,让它返回promise 对象,该函数的作用是2s 之后让数值乘以2
// 2s 之后返回双倍的值
function doubleAfter2seconds(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000);
} )
}
async function testResult() {
let result = await doubleAfter2seconds(30);
console.log(result);
}
testResult();
2秒后输出:
等待promise执行后输出
示例二
function doubleAfter2seconds(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000);
} )
}
async function testResult() {
let first = await doubleAfter2seconds(30);
let second = await doubleAfter2seconds(50);
let third = await doubleAfter2seconds(30);
console.log(first + second + third);
}
testResult();
6秒后输出:
async和await的应用场景
假设我们有如下两个方法
function convertToBase64Data(url) { // 转成base64格式
return new Promise( resolve => {
setTimeout( () => {
resolve('img');
}, 1000);
});
}
function saveToLocal(img) { // 保存到本地
return new Promise( resolve=> {
setTimeout( () => {
resolve('success');
}, 200);
});
}
场景1:
多个异步需要按顺序:图片处理完成然后保存在本地
promise版
function fn1() {
return convertToBase64Data('http://1.jpg').then( base64Data => {
return saveToLocal(base64Data);
})
}
async await版:
async function fn1() {
const base64Data = await download('http://1.jpg');
const result = await saveToLocal(base64Data);
return result;
}
场景2:
图片需要同时处理,但是要按顺序一张一张保存在本地
async function fn2() {
// 同时处理两张
const promise1 = convertToBase64Data('http://1.jpg');
const promise2 = convertToBase64Data('http://2.jpg');
const [data1, data2] = await Promise.all([promise1, promise2]);
// 先保存第一张
const result = await saveToLocal(data1);
// 再保存第二张
const result2 = await saveToLocal(data2);
}
场景3:
多张图片,处理一张保存一张,然后才能处理下一张
async function fn3() {
const imgUrls = ['http://1.jpg', 'http://2.jpg', 'http://3.jpg', 'http://4.jpg', 'http://5.jpg'];
for (let i = 0; i < imgUrls.length; i++) {
const base64Data = await convertToBase64Data(imgUrls[i]);
const result = await saveToLocal(base64Data);
console.log(result);
}
}
场景4:
条件语句
async function fn4(needConvertToBase64) {
const img = await download('http://1.jpg');
if (needConvertToBase64) {
const base64Data = await convertToBase64(img);
return base64Data;
}
return img;
}
场景5:
你可能会这样:调用方法1,使用方法1返回的结果去调用方法2,然后使用两者的结果去调用方法3。
假设有如下业务: 获取用户ID,然后根据ID获取用户信息,然后将两者保存在服务器。
function getUserId() {
return Promise.resolve('123123');
}
function getUserInfo(id) {
return Promise.resolve({name: 'aaron'});
}
function saveToServer(id, userInfo) {
return Promise.resolve('success');
}
你的代码很可能是这样的:
function fn5() {
return getUserId().then( id => { // 拿到id
return getUserInfo(id).then( userInfo => {
return saveToServer(id, userInfo);
});
});
}
使用await:
async function fn5() {// 使用await
const id = await getUserId();
const userInfo = await getUserInfo(id);
return saveToServer(id, userInfo);
}
场景6:
错误处理
使用await,try/catch捕获错误
async function fn6() {
try {
const data = await convertToBase64('http://1.jpg');
const result = await saveToLocal(data);
console.log(result);
} catch (err) {
console.log(err);
}
}
=> { // 拿到id
return getUserInfo(id).then( userInfo => {
return saveToServer(id, userInfo);
});
});
}
使用await:
```js
async function fn5() {// 使用await
const id = await getUserId();
const userInfo = await getUserInfo(id);
return saveToServer(id, userInfo);
}
场景6:
错误处理
使用await,try/catch捕获错误
async function fn6() {
try {
const data = await convertToBase64('http://1.jpg');
const result = await saveToLocal(data);
console.log(result);
} catch (err) {
console.log(err);
}
}