1、Js中常见的异步编程方式?
1)回调函数实现
2)发布订阅、通知
3)事件监听
4)Promise/A+ 和 生成器函数
5)async/await
1.2 回调函数
回调函数就是把任务拆解成两部分,把任务的第二部份单独写在一个函数里面,等到执行完其它任务重新执行这个任务的时候,就直接调用这个函数,从而达到异步效果
let cook = (step1, callback) => {
// 1. 煮牛肉
console.log(`烧水煮${step1}`);
// 2. 放入土豆(5秒后执行)
setTimeout(() => {
let step2 = '放入土豆';
callback(step2);
}, 5000)
};
// 1. 先煮牛肉
cook('牛肉', (data) => {
console.log(data);
});
// 2. 做其它事, 5s后放入土豆
console.log('买土豆');
console.log('洗土豆');
console.log('切土豆');
运行结果:
虽然回调函数能够实现异步,但是回调函数存在以下问题:
1)回调地狱问题:
异步多级依赖的情况下会层层嵌套,代码难以阅读的维护;
2)可能会造成多个异步在某一时刻获取所有异步的结果;
3)异步不支持try/catch回调函数是在下一事件环中取出,
所以一般在回调函数的第一个参数都是用来预置错误对象
4)不能通过return返回结果
2、Promise:
promise,承诺。在代码中我们可以这么理解:此处我先许下个承诺,过了一定时间后我带给你一个结果。
Promise的三种状态
1)Pending
Promise对象实例创建时候的初始状态
2)Fulfilled
成功的状态
3)Rejected
失败的状态
构建Promise
// promise的方法会立刻执行;
// 两个输出都会打印
let promise = new Promise(() => {
console.log('喜欢IT');
});
console.log('就上撩课(itlike.com)');
promise也可以代表未来的一个值
一个promise实例可以多次调用then,当成功后会将结果依次执行
let promise = new Promise(
(resolve, reject) => {
ajax.get(BASEURL + 'api/goods/',
(err, data)=>{
if (err) return reject(err);
resolve(data);
})
});
promise.then(data => {
console.log(data);
});
promise.then(data => {
console.log(data);
});
promise也可以代表一个不用返回的值
// 代表一个用于不会返回的值
let promise = new Promise(
(resolve, reject) => { }
);
promise.then(data => {
console.log(data);
});
Promise.resolve
返回一个Promise实例,这个实例处于resolve状态。
Promise.resolve('成功获取结果')
.then(data=>{
console.log(data);
});
Promise.reject
返回一个Promise实例,这个实例处于reject状态。
Promise.reject('获取结果失败')
.then(data=>{
console.log(data);
},err=>{
console.log(err);
})
Promise.race
该方法用于接收一个数组,数组内都是Promise实例,返回一个Promise实例,这个Promise实例的状态转移取决于参数的Promise实例的状态变化。
当参数中任何一个实例处于resolve状态时,返回的Promise实例会变为resolve状态。如果参数中任意一个实例处于reject状态,返回的Promise实例变为reject状态。
Promise.race(
[readFiles('./a.txt'),
readFiles('./b.txt')]).then(
data=>{
console.log({data})
},(err)=>{
console.log(err)
});
下面通过样例作为演示,我们定义做饭、吃饭、洗碗(cook、eat、wash)这三个方法,它们是层层依赖的关系,下一步的的操作需要使用上一部操作的结果。(这里使用 setTimeout 模拟异步操作)
//做饭
function cook(){
console.log('开始做饭。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('做饭完毕!');
resolve('鸡蛋炒饭');
}, 1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('吃饭完毕!');
resolve('一块碗和一双筷子');
}, 2000);
});
return p;
}
function wash(data){
console.log('开始洗碗:' + data);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('洗碗完毕!');
resolve('干净的碗筷');
}, 2000);
});
return p;
}
使用 then 链式调用这三个方法
cook()
.then(function(data){
return eat(data);
})
.then(function(data){
return wash(data);
})
.then(function(data){
console.log(data);
});
当然上面代码还可以简化成如下:
cook()
.then(eat)
.then(wash)
.then(function(data){
console.log(data);
});