浅析回调函数、Promise、iterator、Generator、async-await的异步方式

想了解这些函数的异步实现,我们就首先说一下什么是异步和同步

异步和同步

异步和同步都是消息通讯机制,都是对"调用一个函数"==来说的

  • 同步:调用一旦开始,调用者必须等到被调用的函数返回了结果才会往下执行
  • 异步:调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。异步方法通常会在另外一个线程中,“真实”地执行,不会阻碍调用者的工作(你可以看成多线程的形式,主函数和调用函数在并发的执行,这样比较好理解,虽然实际上不是这样

举例:你用洗衣机洗衣服
同步:站在洗衣机旁边等到衣服洗完你再晾衣服。
异步:将衣服放进洗衣机,然后你去听歌煮饭,等到洗衣机洗完的信号发出,你再回来晾衣服
同步:
在这里插入图片描述
异步:
在这里插入图片描述

异步的实现

setTimeout、Promise、iterator、Generator、async-await这些都是异步调用的方式
我理解JavaScript中的异步是,将想进行异步的操作封装成一个回调函数,再通过异步调用的方式调用这个回调函数

1.setTimeout

{
    function init() {
        console.log("1");
        setTimeout(() => {
            console.log("2");
        }, 1000);
        console.log("3");
    }
}

输出结果:1 3 2
由此可以发现setTimeout视乎有异步的功能

2.使用回调函数实现

{
    // 回调地狱
    function ajax(cb) {
        setTimeout(() => {
            cb && cb(() => {
                console.log('任务2')
            })
        }, 1000)
    }
    ajax((cb2) => {
        console.log('任务1')
        setTimeout(() => {
            cb2 && cb2()
        },1000)
    })
}

使用setTimeout实现异步请求,异步请求次数少还好,多了就陷入了回调地狱(比如:前端向后端请求查询该用户的id,再通过返回的id,请求查询用户的基本信息),这样的代码就不容易让人阅读和书写

3.Promise

为了解决回调地狱的问题,大佬们设计了Promise这种语法糖,这语法糖真香

{
    function ajax() {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(), 1000)
        })
    }
    ajax()
        .then(() => {
            console.log('任务1')
            return new Promise(resolve => {
                setTimeout(() => resolve(), 1000)
            })
        })
        .then(() => {
            console.log('任务2')
        })
}

将想进行异步的操作封装成一个回调函数,再通过异步调用的方式调用这个回调函数,Promise里设计的成功失败函数,让代码更加灵活,也减少了代码出现卡死的情况

4.iterator

有些大佬发现iterator也有异步的功能

{
    const arr = [1, 2, 3]
    const fn = arr[Symbol.iterator]()
    console.log(fn.next())
    console.log(fn.next())
    console.log(fn.next())
    console.log(fn.next())
}

当fn调用next()函数的时候才会遍历下一个元素,这视乎也有一定的异步的功能,为了方便程序员使用,设计出了Generator和async-await两种语法糖

5.Generator

Generator就是iterator的语法糖
Generator函数就是普通的function函数后面加个*
每个yield相当于数组里的一个元素,.next()相当于移动当前数组元素的指针

模拟不断查询是否支付成功

{
    function fn1() {
        return new Promise(resolve => {
            setTimeout( () => {
                console.log('查询中')
                resolve({code: 0})
            },1000)
        })
    }

    const getStatus = function* () {
        yield fn1()
    }

    function autoGetStatus() {
        const gen = getStatus()
        const status = gen.next()
        status.value.then(res => {
            if(res.code === 0) {
                console.log('用户付款成功')
            } else {
                console.log('暂未付款')
                setTimeout( () => autoGetStatus(), 500)
            }
        })
    }

    autoGetStatus()
}

这种方式好像不是很直观,程序员又设计了一种用一种看起来像同步编程的方式来进行异步编程的语法糖async-await

6.async-await

优化版:模拟不断查询是否支付成功

{
    function findPayState() {
        return new Promise((resolve, reject)=>{
            setTimeout(() => {
                console.log('查询中');
                resolve({code: 0})
            }, 1000);
        })
    }

    async function autoGetState() {
        const json =  await findPayState()
        if(json.code === 0){
            console.log('支付成功');
        }else{
            autoGetState()
        }
    }
    autoGetState()
}
手写async和await的实现可以通过使用generator函数和Promise来实现。首先,我们可以将async函数转换为一个generator函数。然后,我们可以编写一个自动执行的函数来处理generator函数中的yield语句,并使用Promise来处理异步操作。 以下是一个手写的async和await的示例代码: ```javascript function asyncToGenerator(generatorFunc) { return function () { const iterator = generatorFunc.apply(this, arguments); return new Promise((resolve, reject) => { function step(key, arg) { let generatorResult; try { generatorResult = iterator[key](arg); } catch (error) { reject(error); return; } const { value, done } = generatorResult; if (done) { resolve(value); } else { return Promise.resolve(value).then( (val) => step("next", val), (err) => step("throw", err) ); } } step("next"); }); }; } const getData = () => new Promise((resolve) => setTimeout(() => resolve("data"), 1000)); const test = asyncToGenerator(function* testG() { const data = yield getData(); console.log('data: ', data); const data2 = yield getData(); console.log('data2: ', data2); return 'success'; }); test().then(res => console.log(res)); ``` 在这个示例中,我们定义了一个名为`asyncToGenerator`的函数,它接受一个generator函数作为参数,并返回一个包装了Promise的自动执行函数。 在`test`函数中,我们使用`yield`关键字来暂停执行,并使用`getData`函数返回的Promise来处理异步操作。当Promise resolve后,generator函数会继续执行,并将结果传递给下一个yield语句。 最后,我们使用`.then`方法来处理test函数的返回值。 这样,我们就实现了一个手写的async和await的功能。注意,这只是一个简化的实现,真正的async和await功能更为复杂,包含更多的特性和错误处理机制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [手写async await的最简实现(20行搞定)!阿里字节面试必考](https://blog.csdn.net/xgangzai/article/details/106536325)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [手写async await的以及深度挖掘(一挖到底)](https://blog.csdn.net/JIANYMN/article/details/123229551)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Top丶super航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值