javascript - 异步与传统多线程比对

github原文

子非鱼安知鱼之乐

仔细想想也写了1年多javascript了,从c#入坑JS后,里里外外也踩了不少坑。本质上还是两种语言的思维不一样。像之前c#,一个线程就是执行一件事情,在我看来大部分逻辑都是可以用顺序,判断和循环来解决的。所以一开始写JS,对异步,回调,甚至promise都很懵圈。不过既然存在就有道理,毕竟当前执行线程一旦阻塞后那WEB页面就卡死,一切就凉凉了。于是我也简单整理了一下我接触过的利用多线程和异步分别去实现非阻塞I/O密集型任务都方式。

多线程模型开发

之前做WPF时,.net提供了一个BackgroundWorker的类库。不得不说微软开发体验好,该提供都都提供了。。
MSDN对应BackgroundWorker文档

private void InitializeBackgroundWorker()
{
    backgroundWorker1.DoWork += new DoWorkEventHandler         (backgroundWorker1_DoWork);
    backgroundWorker1.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(
        backgroundWorker1_RunWorkerCompleted);
    backgroundWorker1.ProgressChanged += 
        new ProgressChangedEventHandler(
    backgroundWorker1_ProgressChanged);
}
复制代码

DoWork 事件是执行都任务
RunWorkerCompleted 任务执行完后触发都事件
ProgressChanged 执行中进度获取
实际我们开发都时候,流程是这样,原谅我灵魂画手
uiandthread


用子线程去执行网络请求,读写文件等操作,待子线程执行完毕,将结果直接返回给UI线程。如果UI线程需要进度条,也可以

异步开发

javascript里就简单多了。打个比方

    request('api', (res) => {
        成功回调
    }, () => {
        失败回调
    });
复制代码

但是回调用多了也恶心,有时候数据流逻辑上是同步使用,比如我必须得到这个数据结果才能下一步网络请求,下一步网络请求的结果拿来去做下下步请求。

    request('api', (res) => {
        成功回调
        request('api2', res, (res2) => {
            成功回调
            request('api3', res2, (res) => {
                成功回调
            }, () => {
                失败回调
            });
        }, () => {
            失败回调
        });
    }, () => {
        失败回调
    });
复制代码

所以Promise出现了。Promise,我个人简单总结就是把嵌套逻辑摆平为同步代码逻辑。

    request('api')
    .then(res => {
        return request('api2', res)
    })
    .then(res2 => {
        return request('api3', res2)
    })
    .then(res3 => {
        成功回调
    })
    .catch(e => {
        失败回调
    });
复制代码

这样代码看起来就没那么乱了。不过,这样就最好了嘛?自然不是,既然都用到promise了,直接撸上await/async更是美滋滋。

    async test() {
        let res = await request('api');
        let res2 = await request('api2', res);
        let res3 = await request('api3', res2);
    }
复制代码

注意:函数体内如果使用await关键字则该函数体必须用async标志。这样写起来,跟写java,c#等代码如出一辙了。(后来听说C#也加上了async/await异步方法)。对了,改为同步写法后,我们对异常处理就更简单了。

    async test() {
        try {
            let res = await request('api');
            let res2 = await request('api2', res);
            let res3 = await request('api3', res2);
        } catch(e) {
            错误处理
        }
    }
复制代码

注意: try/catch只能捕捉同步代码的异常,如果写成下面那样,

    test() {
        try {
            let res = request('api');
            let res2 = request('api2', res);
            let res3 = request('api3', res2);
        } catch(e) {
            错误处理
        }
    }
    test2() {
        try {
            request('api')
            .then(res => {
                return request('api2', res)
            })
            .then(res2 => {
                return request('api3', res2)
            })
            .then(res3 => {
                成功回调
            })
            .catch(e => {
                失败回调
            });
        } catch(e) {
            错误处理
        }
    }
复制代码

可是无法正确catch到异常哟。有时候写nodejs时,出错了需要重试,这样用try/catch抓到异常后便可直接进行重试操作,远比之前回调方式要简单的多。而且异常也可一直抛出到外部,由外部调用代码去处理。

    async main() {
        try {
           await test();
        } catch(e) {
            错误处理
            await test();
        }
    }
    async test() {
        let res = await request('api');
        let res2 = await request('api2', res);
        let res3 = await request('api3', res2);
        return res3
    }
复制代码

总结

线程模型同步逻辑,异常捕捉与处理等都比异步回调方式要友好。但是线程创建,销毁和切换是有开销都。
JS的异步回调,免去线程都开销。但是回调代码读起来也挺累的哟。如果大家用ES6和typescipt的话,用async/await的话就会友好很多。

转载于:https://juejin.im/post/5cfcbedee51d45595319e30f

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值