Promise
异步编程
- 回调函数实现
- 事件监听
- 发布订阅
- Promise/A+和生成器函数
- asynv/await
回调函数
回调的特点是error first,调用回调函数的时候第一个参数永远是错误对象,错误对象也是优先需要进行判断的
const fs = require('fs')
fs.readFile('./1.txt', 'utf8', function(err, data){
if(err){
console.log(err);
}else{
console.log(data);
}
})
回调函数的问题
- 无法捕获错误 try catch
- 不能return,执行和回调是两个不同的执行栈
- 回调地狱
这种恶魔金字塔有以下问题:
- 非常难看
- 非常难以维护
- 效率比较低,因为他们是串行的
fs.readFile('./template.txt', 'utf8', function(err, data){
fs.readFile('./data.txt', 'utf8', function(err, data){
fs.readFile('./data.txt', 'utf8', function(err, data){
})
})
})
事件发布订阅实现
- 通过事件发布订阅来实现
const EventEmitter = require('events');
let eve = new EventEmitter();
let html = {}; // temmplate data
eve.on('ready', function(key, value){
html[key] = value;
if(object.keys(html).length == 2){
console.log(html
}
})
fs.readFile('./template.txt', 'utf8', function(err, data){
eve.emit('ready', 'template', template);
})
fs.readFile('./1.data', 'utf8', function(err, data){
eve.emit('ready', 'data', data);
})
生成器generator
生成器是一个函数,可以用来生成迭代器
生成器函数和普通函数不一样,普通函数是一旦调用一定会执行完
但是生成器函数中间可以暂停,可以执行一会休一会
生成器有一个特点,需要加个*
生成器有若干个阶段, 使用yield区分
function *go(){
console.log(1);
let b = yield 'a';
console.log(2);
let c = yield 'b'
console.log(3);
return c;
}
生成器函数和普通函数不一样,调用它的话函数并不会立刻执行
它会返回此生成器的迭代器,迭代器是一个对象,每调用一次next就可以返回一个值对象,此对象有两个属性,一个是value就是yield后面那个值,一个是done表示是否迭代完成
let it = go()
let r1 = it.next();
console.log(r1); // {value: 'a' , done: false}
let r2 = it.next('B');
console.log(r2); // { value:'B' , done: false}
next第一次执行不需要参数,传参数是没有意义。参数会赋值给yield前面的变量
let b = yield 'a'
这一行实现输入和输出,本次的输出放在yield后面,下次的输入放在yield前面
Promise
let p = new Promise(function(resolve, reject){
setTimeout(function(){
let num = Math.random();
if(num < .5){
resolve(num);
} else {
reject('失败')
}
})
});
p1.then(function(data){
console.log(data)
}, function(err){
console.log(err)
});
链式操作用法
function runAsync1(){
var p = new Promise(function(resolve, reject{
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('随便什么数据1')
}, 1000)
}))
return p
}
function runAsync2(){
var p = new Promise(function(resolve, reject{
setTimeout(function(){
console.log('异步任务2执行完成');
resolve('随便什么数据2')
}, 2000)
}))
return p
}
function runAsync3(){
var p = new Promise(function(resolve, reject{
setTimeout(function(){
console.log('异步任务3执行完成');
resolve('随便什么数据3')
}, 3000)
}))
return p
}
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
异步任务3执行完成
随便什么数据3
或者直接return 数据
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return '直接返回数据'; //这里直接返回数据})
.then(function(data){
console.log(data);
});
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
直接返回数据
reject用法
reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调
function getNumber(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num);
}
else{
reject('数字太大了');
}
}, 2000);
});
return p;
}
getNumber()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason, data){
console.log('rejected');
console.log(reason);
}
);
1 或者 数字太大了
catch用法
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
如果执行的时候发生异常,就中止代码执行,将异常传递给catch的回调函数处理
Promise.all
Promise.all:会接受一个promise数组,如果promise全部完成了这个promise才会成功,如果有一个失败,那么这个promise就整个失败了
Promise.race
Promise.race 会接受一个promise数组, 只要一个成功,则就成功了,只要一个失败就失败了