大家都知道nodejs很快,为什么会这么快呢,原因就是node采用异步回调的方式来处理需要等待的事件,使得代码会继续往下执行不用在某个地方等待着。但是也有一个不好的地方,当我们有很多回调的时候,比如这个回调执行完需要去执行下个回调,然后接着再执行下个回调,这样就会造成层层嵌套,代码不清晰,很容易进入“回调监狱”,就容易造成下边的例子:
async(1, function(value){
async(value, function(value){
async(value, function(value){
async(value, function(value){
async(value, function(value){
async(value, final);
});
});
});
});
});
这样的写法会让人崩溃,那么有什么办法可以解决这个问题呢,或者有其他别的写法吗?答案是有的,es6新出的promise对象已经es7的async await都可以解决这个问题。
(1)我们接下来首先谈一谈promise,下面是定义一个promise对象
let a = 1;
let promise = new Promise(function(resolve, reject){
if(a==10){
resolve('成功了');
}else{
reject('失败了');
}
});
定义的promise对象接受成功和失败回调可以这样接收
promise.then(res=>{
console.log(res); //成功回调
},err=>{
console.log(err); //失败回调
})
也可以使用catch接收失败回调
promise.then(res=>{
console.log(res); //成功回调
}).catch(err=>{
console.log(err); //失败回调
})
下面是promise的一些api
1、Promise.resolve()
使用方法
let p1 = Promise.resolve('aaa');
p1.then(res=>{
console.log(res);
})
等同于
let p1 = new Promise(resolve =>{
resolve('aaa')
});
p1.then(res=>{
console.log(res);
})
2、Promise.reject()
3、Promise.all() // 所有的都有完成,相当于 且
4、Promise.race() // 完成一个即可,相当于 或
(2)接下来我们来看一个使用node来异步读取文件的实例来展示
1、使用promise来实现
const fs = require('fs');
//简单封装 fs封装成一个promise
const readFile = function (fileName){
return new Promise((resolve, reject) =>{
fs.readFile(fileName, (err, data) =>{
if(err) reject(err);
resolve(data);
});
});
}
//promise
readFile('data/a.txt').then(res=>{
console.log(res.toString());
return readFile('data/b.txt');
}).then(res=>{
console.log(res.toString());
return readFile('data/c.txt');
}).then(res=>{
console.log(res.toString());
})
2、使用generator来实现
const fs = require('fs');
//简单封装 fs封装成一个promise
const readFile = function (fileName){
return new Promise((resolve, reject) =>{
fs.readFile(fileName, (err, data) =>{
if(err) reject(err);
resolve(data);
});
});
}
//generator
function * gen(){
yield readFile('data/a.txt');
yield readFile('data/b.txt');
yield readFile('data/c.txt');
}
let g1 = gen();
g1.next().value.then(res=>{
console.log(res.toString());
return g1.next().value;
}).then(res=>{
console.log(res.toString());
return g1.next().value;
}).then(res=>{
console.log(res.toString());
})
看起来优雅了不少
3、使用async来实现
const fs = require('fs');
//简单封装 fs封装成一个promise
const readFile = function (fileName){
return new Promise((resolve, reject) =>{
fs.readFile(fileName, (err, data) =>{
if(err) reject(err);
resolve(data);
});
});
}
//async
async function fn(){
let f1 = await readFile('data/a.txt');
console.log(f1.toString());
let f2 = await readFile('data/b.txt');
console.log(f2.toString());
let f3 = await readFile('data/c.txt');
console.log(f3.toString());
}
fn();
4、异步的一些测试实例
(1)yield和promise共同使用
let mypromise = new Promise((resolve) => {
resolve("123")
})
mypromise.then((d) => {
setTimeout(() => {
console.log('setTimeoutResult', d);
return d;
}, 10000)
})
let result = yield mypromise;
console.log('result', result);
打印结果
let result = yield call(testPromise);
console.log('result', result);
function testPromise() {
return Promise.resolve("123").then(() => {
return Promise.resolve("456")
})
}
打印结果
上述实例改成如下
function testPromise() {
return Promise.resolve("123").then(() => {
return Promise.resolve("456").then(null);
})
}
打印结果依然如此
(2)resolve返回另一个promise
下面代码中,p1是一个Promise,3秒之后变为rejected。p2的状态在1秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了2秒,p1变为rejected,导致触发catch方法指定的回调函数。
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail
(3)async返回一个promise
getPromise() {
return new Promise((resolve, _reject) => {
setTimeout(() => {
console.log("getPromise");
resolve("getPromiseValue")
}, 3000);
})
}
getPromise2() {
return new Promise((resolve, _reject) => {
setTimeout(() => {
console.log("getPromise2");
resolve("getPromiseValue2")
}, 3000);
})
}
async test() {
let promise1 = await this.getPromise()
console.log("promise1", promise1);
setTimeout(() => {
console.log("test");
}, 5000);
let promise2 = await this.getPromise2()
console.log("promise2", promise2);
return "test value"
}
this.test().then((val) => {
console.log("val", val);
})
打印结果如下
(4)dva中yield理解
let test = yield put({ type: "getDingLocation", message });
test.then((val) => {
console.log("val", val);
});
/**
* 获取钉钉定位
*/
*getDingLocation({ message }, { put, call }) {
try {
let res = { latitude: "31.178414", longitude: "121.604919", address: "上海市浦东新区荣科路" };
yield put({ type: "input", data: { userLocation: res } });
yield put({ type: "getTaskData", message });
console.log("getDingLocation", res);
return "getDingLocation";
}
}
打印结果
yield返回的是一个promise,promise结果是generator函数的返回值
换一个写法
let test = yield yield put({ type: "getDingLocation", message });
// test.then((val) => {
// console.log("val", val);
// });
console.log("test", test);
打印结果,可以看出两者结果相同
以上就是一些简单的理解和学习记录。