在开发过程中经常会遇到一些异步操作,比如ajax
请求,node
读取写入文件,定时任务等等。通常情况下需要捕获异步返回的数据,从而进行下一步操作,下面介绍一下几种处理异步执行的方法
CallBack回调事件
callback
,事件回调,异步处理完成,通过事件的调用,从而达到异步处理要求。经典的有ajax
请求,node
文件操作等,下面看一下node
非阻塞代码实例:
var fs = require("fs");
var path = require("path");
fs.readFile(path.join(__dirname, '../public/user.json'), (err, data) => {
if(err) throw err;
let list = JSON.parse(data);
console.log(list);
})
这里readFile
函数的第二个参数便是异步处理完成的回调函数
Promise
Promise
是开发中经常用到的异步处理方法,下面介绍下promise
的常用方法:
- 基本使用,已
setTimeout
为例,定义一个promise
的对象,一分钟后生成一个10
以内的随机数,并判断随机数的大小模拟异步操作成功失败,大于5
则成功,在then
获取random
的值,失败同理
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
let random = Math.random() * 10;
if(random > 5)
resolve(random);
else
reject(random);
}, 1000)
})
promise
.then(res => {
console.log(res, 'res')
})
.catch(err => {
console.log(err, 'rej')
})
Promise.all
:开发过程中有时会遇到,需要同时处理几个接口返回数据的情况,这种就需要捕获几个接口都结束的状态,promise.all
就解决了这个问题。该方法接收一个数组作为参数,数组里面的每一项都为一个promise
对象,具体如下,新建两个promise对象,一个1s返回 ‘promise1’,一个2s返回 ‘promise2’,使用all之后便在2s后返回一个数组:['promise1', 'promise2']
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise1')
}, 1000);
});
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise2');
}, 2000);
})
Promise.all([promise1, promise2])
.then(res => {
console.log(res, 'res'); // 2s 后打印 ['promise1', 'promise2']
})
.catch(err => {
console.log(err, 'rej');
})
如果有一个promise
失败了,则在catch
中捕获的便是该promise
对象的错误信息,如下:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise1')
}, 1000);
});
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('promise2');
}, 2000);
})
Promise.all([promise1, promise2])
.then(res => {
console.log(res, 'res');
})
.catch(err => {
console.log(err, 'rej'); // 2s 后打印出 'promise2'
})
- promise.race,竞速,不管成功或者失败,都返回最先完成的promise对象,下列代码便返回最快的1s执行完成的对象
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise1')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise2')
}, 2000)
})
Promise.race([promise1, promise2])
.then(res => {
console.log(res, 'res') // 打印出最快1s完成的'promise1'
})
.catch(err => {
console.log(err, 'rej') //错误也是同理
})
async awite
promsie解决了异步的困扰,但是存在一个问题:链式回调。这使得代码不容易阅读,async写法则解决了这个问题。
- async函数返回的是一个
promise
的对象
getResult: async function (vm) {
return 'hello word'
}
getResult.then(res => {
console.log(res); // hello word
})
awite
必须在有标记async
的函数中使用,当执行到awite标记时,并且awite后是一个promise,便会等待promise对象执行完成,才会继续往下执行。成功则返回r1的数据,被回调函数then捕获。 当promise失败时便会跳出,并被函数catch捕获
function getResult() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let r1 = Math.ceil(Math.random() * 10);
console.log(r1);
resolve(r1);
}, 1000)
})
}
(async function(){
let r1 = await getResult();
console.log('等待r1完成后执行'); //这里会在1s后执行,getResult失败则不会执行这里
return r1;
})()
.then(res => {
console.log(res); // getResult成功执行后会返回随机生成的 r1
})
.catch(err => {
console.log(err); // getResult执行失败后,会被catch捕获,包括错误信息
})
- 解决
promise
链式回调问题:在开发过程中会存在一个接口调用需要另一个接口返回的数据时,需要在promsie.then
中继续调用接口,当这种关系存在很多个的时候就会出现下面这种情况。随机生成三个数,求三个数相加的和,最后的链式回调就看起来特别乱,也不好管理。(当然这里可以用promise.all
来实现,但是一旦接口中请求参数需要依赖上一个接口返回的结果则还是需要链式回调)
function getR1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let r1 = Math.ceil(Math.random() * 10);
resolve(r1);
}, 1000);
});
}
function getR2(r1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let r2 = Math.ceil(Math.random() * 10);
resolve(r2);
}, 1000);
});
}
function getR3(r1, r2) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let r3 = Math.ceil(Math.random() * 10);
resolve(r1 + r2 + r3);
}, 1000);
});
}
getR1()
.then(r1 => {
console.log(r1); // 1s 后打印一个随机数的值
getR2(r1)
.then(r2 => {
console.log(r1 + r2); // 2s 后打印二个随机数的和
getR3(r1, r2)
.then(r3 => {
console.log(r1 + r2 + r3); // 3s 后打印三个随机数的和
})
})
})
async
完美解决,下面代码看起来是不是清晰多了
(async function(){
let r1 = await getR1();
let r2 = await getR2();
let r3 = await getR3();
console.log('等待3s后执行:', r1 + r2 + r3);
})()
promise对象执行失败捕获
(async function(){
let r1 = await getR1().catch(err => {
console.log(err);
});
})()