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

github原文javascript

子非鱼安知鱼之乐

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

多线程模型开发

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

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 git


用子线程去执行网络请求,读写文件等操做,待子线程执行完毕,将结果直接返回给UI线程。若是UI线程须要进度条,也能够

异步开发

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

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

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

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

因此Promise出现了。Promise,我我的简单总结就是把嵌套逻辑摆平为同步代码逻辑。api

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

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

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的话就会友好不少。

相关文章
相关标签/搜索