谈谈JS异步处理(Promise、generator、async)

大家都知道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);

打印结果
实例1

let result = yield call(testPromise);
console.log('result', result);
function testPromise() {
  return Promise.resolve("123").then(() => {
    return Promise.resolve("456")
  })
}

打印结果
实例1
上述实例改成如下

function testPromise() {
  return Promise.resolve("123").then(() => {
    return Promise.resolve("456").then(null);
  })
}

打印结果依然如此
实例1

(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);

打印结果,可以看出两者结果相同
在这里插入图片描述

以上就是一些简单的理解和学习记录。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值