关于javascript:jsasync函数与其他异步操作

1.其余异步操作

  1. 传统的异步操作
  2. Generator的异步操作

异步:工作的不间断执行,跳跃执行,在一个工作阻塞时主线程去执行其余工作,阻塞工作接管到执行信号时,再从新增加到工作队列中执行

1.1传统的异步操作

传统的异步操作

  1. 回调函数
  2. 事件监听
  3. 公布/订阅
  4. Promise对象

1.1.1回调函数(callback)

  • 将一个工作分成多段,嵌套的模式去执行

    fs.readFile('/etc/passwd' , 'utf-8', function(err , data){
      if (err) throw err;
      console.log(data);
    });

    readFile的第三个参数就是一个回调函数,在申请文件胜利后才会调用
    回调函数能够实现程序的异步执行

回调天堂callback hell

//不同的工作
function toEat(val, fn) {
    setTimeout(() => {
        fn(val)
    }, 2000);
}
function toDrink(val, fn) {
    setTimeout(() => {
        fn(val)
    }, 1000);
}

function toKTV(val, fn) {
    setTimeout(() => {
        fn(val)
    }, 500);
}
//按程序执行工作
toDrink("吃火锅", data => {
    console.log(data);
    toDrink("喝啤酒", data => {
        console.log(data);
        toKTV("唱歌", data => {
            console.log(data);
        })
    })
})
//"吃火锅"
//"喝啤酒"
//"唱歌"

在一个工作的回调函数中嵌套其余工作
其余工作也有回调函数,这样的层层嵌套当呈现谬误时代码很难保护

1.1.2 Promise

//工作封装Promise
function toResolve(data, delay) {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(data)
        }, delay);
    })
    return promise
}
//不同的工作
function toEat(val) {
    return toResolve(val, 2000)
}
function toDrink(val) {
    return toResolve(val, 1000)
}
function toKTV(val) {
    return toResolve(val, 500)
}
//按程序执行工作
toEat("吃火锅").then(val => {
    console.log(val);
    return toDrink("喝啤酒")
}).then(val => {
    console.log(val);
    return toKTV("唱歌")
}).then(val => {
    console.log(val);
}).catch(res => {
    console.log(res);
})
//吃火锅
//喝啤酒
//唱歌

定时执行回调函数改为定时扭转Promise状态
构造更加清晰
然而因为原工作的Promise封装,代码冗余,因为then的沉积,语义变得不分明

1.2.Generator的异步操作

依然应用下面封装的Promise工作,应用Generator去异步执行

//生成器函数
function* asyncJob() {
    let val1 = yield toEat("吃火锅")
    console.log(val1);
    let val2 = yield toDrink("喝啤酒")
    console.log(val2);
    let val3 = yield toKTV("唱歌")
    console.log(val3);
}
//生成器函数的执行器
function runGenerator(fn) {
    let iter = fn()
    let { value, done } = iter.next()
    value.then(val1 => {
        let { value, done } = iter.next(val1)
        value.then(val2 => {
            let { value, done } = iter.next(val2)
            value.then(val3 => {
                iter.next(val3)
            })
        })
    })
}
//开始执行异步工作
runGenerator(asyncJob)
//吃火锅
//喝啤酒
//唱歌

以toEat为例,察看异步工作如何执行的

  1. 调用生成器函数的执行器
  2. 调用生成器函数,返回迭代器对象
  3. 第一次调用迭代器上的next办法:执行至第一个yild,调用toEat函数,返回一个Promise对象作为next返回值的value属性,解构取value的值
  4. 在value上调用then:接管resolve中的值(会提早2s),通过第二次调用next将接管的值赋值给第一个yield
  5. 能够在第一个yield和第二个yield之间解决toEat返回的值
  6. 对于第二个next的返回值能够解构进行同样的操作

重点
调动next后产生了什么
next参数传递的准则
Promise的解决与状态变动

2.async函数

Generator的语法糖 – 使异步操作更加简略

应用下面封装的Promise工作

//生成器的异步工作
async function asyncJob() {
    let val1 = await toEat("吃火锅")
    console.log(val1);
    let val2 = await toDrink("喝啤酒")
    console.log(val2);
    let val3 = await toKTV("唱歌")
    console.log(val3);
}
//开始执行异步工作
asyncJob()
//吃火锅
//喝啤酒
//唱歌

async代替了生成器中星号*,用await代替生成器中的yield
与生成器的异步操作相比,async函数不必手写执行器,自带执行器
间接调用async函数就能够执行外部的工作

async函数对Generator的改良

  • 内置执行器
    Generator函数的执行须要执行器,手写或者引入co模块,而async函数自带执行器,能够让其像一般函数一样执行
  • 更好的语义
    async与await比星号*与yield的语义表白更清晰
  • 更广的适用性
    co模块指定yield后只能是Thunk函数Promise对象,而async函数的await后能够是Promise对象原始类型的值
  • 返回值是Promise
    Genetator的返回值是迭代器对象,async函数返回的是一个Promise对象

    async函数中有return时,默认return的值Promise.resolve()转成Promise对象,在内部用then能够接管

2.1 async函数的错误处理

已知async返回的是一个Promise,能够在内部捕捉谬误

//生成器的异步工作
async function asyncJob() {
    let val1 = await toEat("吃火锅").then(() => {
        throw new Error("饭店开张了")
    })
    console.log(val1);
    let val2 = await toDrink("喝啤酒")
    console.log(val2);
    let val3 = await toKTV("唱歌")
    console.log(val3);
}

//开始执行异步工作
asyncJob().catch(res => {
    console.log(res);
})
// Error:饭店开张了

一条await后的语句出错时,后续不再执行,间接将谬误抛出

try…catch

//生成器的异步工作
async function asyncJob() {
    try {
        let val1 = await toEat("吃火锅").then(() => {
            throw new Error("饭店开张了")
        })
        console.log(val1);
    } catch (e) {
        console.log(e);

    }
    try {
        let val2 = await toDrink("喝啤酒")
        console.log(val2);
        let val3 = await toKTV("唱歌")
        console.log(val3);
    } catch (e) {
        console.log(e);
    }

}
//开始执行异步工作
asyncJob().catch(res => {
    console.log(res);
})
// Error:饭店开张了
// 喝啤酒
// 唱歌

相互无影响的工作放在不同的try…catch代码块中
相互有影响的工作放入雷同的try…catch代码块中

2.2 async函数中的并发

//生成器的异步工作
async function asyncJob() {

    let val = await Promise.all([toEat("吃火锅"), toDrink("喝啤酒")])
    console.log(val);
    let val3 = await toKTV("唱歌")
    console.log(val3);
}
//开始执行异步工作
asyncJob().catch(res => {
    console.log(res);
})
// ['吃火锅','喝啤酒']
// "唱歌"

同样也能够应用Promise.any() Promise.race()等办法

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理