image.png

什么是异步

有异步肯定就有同步,那我们就比较的来看。

1、同步:同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;

2、异步:异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

JS是单线程的,天生异步,适合IO密集型,不适合CPU密集型

为什么要用异步编程

在前端开发中,我们经常需要和网络请求或浏览器的事件交互,这些操作可能会耗费大量的时间,而同步代码会阻塞程序的执行,导致页面失去响应,用户体验不佳。

异步编程可以在请求发出后,继续执行程序的其余部分,无需等待请求响应。当请求响应到达时,异步代码可以接收并处理响应。这样可以提高页面的响应速度和用户体验。在Node.js中,异步编程还可以避免阻塞整个应用程序,提高应用程序的并发性能。

异步编程怎么做

回调函数

setTimeout(function () {
    console.log('Time out');
}, 1000);

定时器里面的匿名函数就是一个回调函数,通过定时器把同步操作编程异步

回调函数的优点便是:简单、容易理解、优化了程序执行速度

缺点就是代码长了会出现回调地狱,还存在一系列控制反转等信任问题

Promise

Promise解决的是回调函数处理异步的第2个问题:控制反转。Promise在一定程度上解决了回调地狱的问题,Promise在一定程度上其实改善了回调函数的书写方式,无论有再多的业务依赖,通过多个then(…)来获取数据,让代码只在纵向进行扩展

        const p1 = Promise.resolve(1) 
        const p2 = Promise.resolve(Promise.resolve(3))
        const p3 = Promise.resolve(Promise.reject(4))
        p1.then(value => {
            console.log('p1', value)
        })
        p2.then(value => {
            console.log('p2', value)
        })
        p3.catch(reason => {
            console.log('p3', reason)
        })

生成器Generator

生成器Generator是ES6中定义的,它是一种顺序、看似同步的异步流程控制表达风格。

在这之前我们先看看两个ES6新增的协议:可迭代协议迭代器协议

可迭代协议(for of循环)

允许对象定义他的可迭代行为,比如在for of结构中,哪些值可以遍历到。在js中的某些类型是内置好的可迭代对象,比如:字符串、数组、类型数组、Map对象、Get对象等。而Object类型不可迭代。这些内置可迭代对象可以进行迭代的原因是内部实现了@@iterator 方法,即在该对象或该对象的原型链上有Symbol.iterator属性实现了@@iterator 方法。

迭代器协议(Iterator对象)

定义了产生一系列值的标准方式。一个对象必须实现next()方法,才能成为迭代器。 next() 方法必须返回一个对象,该对象应当有两个属性: done 和 value done(boolean)如果迭代器可以产生序列中的下一个值,则为 false。 value 迭代器返回的任何 JavaScript 值

用Generator实现异步

const fs = require('fs');
const co = require('co');
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);

function* read() {
    yield readFile(A, 'utf-8');
    yield readFile(B, 'utf-8');
    yield readFile(C, 'utf-8');
    //....
}
co(read()).then(data => {
    //code
}).catch(err => {
    //code
});

也就是说,Generator生成器解决了Promise没有解决的纵向扩展。

Async/Await

Async/Await是ES7新引入的概念。他就是结合了上面所说的Promise和Generator,用同步的方式实现异步操作。

我们简单看一段使用async/await的代码:

        async function fn3() {
            try {
                const value = await fn2() // await右侧表达式为promise,得到结果promise成功的value
                console.log('value', value);
            } catch (error) {
                console.log('失败的结果', error)
            }
        }
        fn3()

可以看出,用的同步的书写方式,只需要把异步的东西用Promise封装出去,然后使用await调用就可以了,也不需要像Generator一样需要手动控制next()执行。

目前来说,Async/Await是最好的异步编程方案了。