第4篇:也许是终极异步解决方案之细说Async专题

上一章咱们了解了co与Generator结合的异步编程解决方案。javascript

我知道你想说什么,写一个异步调用还得引入一个npm包(虽然是大神TJ写的包)。html

妈卖批的npm!

固然是不存在的。若是一个特性足够重要,社区的呼声足够高,它就必定会被归入标准的。立刻咱们要介绍的就是血统纯正的异步编程家族终极继承人——爱新觉罗·async。前端

往期:

  1. 第1篇:事件循环之细说Async专题
  2. 第2篇:迟到的承诺之细说Async专题
  3. 第3篇:状态机之细说Async专题
  4. 第4篇:也许是终极异步解决方案之细说Async专题
import co from 'co';

function fetchByName(name) {
    const url = `https://api.github.com/users/${name}/repos`;
    return fetch(url).then(res => res.json());
}

co(function *gen() {
    const value1 = yield fetchByName('veedrin');
    console.log(value1);
    const value2 = yield fetchByName('tj');
    console.log(value2);
});
function fetchByName(name) {
    const url = `https://api.github.com/users/${name}/repos`;
    return fetch(url).then(res => res.json());
}

async function fetchData() {
    const value1 = await fetchByName('veedrin');
    console.log(value1);
    const value2 = await fetchByName('tj');
    console.log(value2);
}

fetchData();

看看这无缝升级的体验,啧啧。java

灵活

别被新的关键字吓到了,它其实很是灵活。git

async function noop() {
    console.log('Easy, nothing happened.');
}

这家伙能执行吗?固然能,老伙计仍是你的老伙计。github

async function noop() {
    const msg = await 'Easy, nothing happened.';
    console.log(msg);
}

一样别慌,仍是预期的表现。npm

只有当await关键字后面是一个Promise的时候,它才会显现它异步控制的威力,其他时候人畜无害。编程

function fetchByName(name) {
    const url = `https://api.github.com/users/${name}/repos`;
    return fetch(url).then(res => res.json());
}

async function fetchData() {
    const name = await 'veedrin';
    const repos = await fetchByName(name);
    console.log(repos);
}

虽说await关键字后面跟Promise或者非Promise均可以处理,但对它们的处理方式是不同的。非Promise表达式直接返回它的值就是了,而Promise表达式则会等待它的状态从pending变为fulfilled,而后返回resolve的参数。它隐式的作了一下处理。json

注意看,fetchByName('veedrin')按道理返回的是一个Promise实例,可是咱们获得的repos值倒是一个数组,这里就是await关键字隐式处理的地方。api

另外须要注意什么呢?await关键字只能定义在async函数里面。

const then = Date.now();

function sleep(duration) {
    return new Promise((resolve, reject) => {
        const id = setTimeout(() => {
            resolve(Date.now() - then);
            clearTimeout(id);
        }, duration * 1000);
    });
}

async function work() {
    [1, 2, 3].forEach(v => {
        const rest = await sleep(3);
        console.log(rest);
        return '睡醒了';
    });
}

work();

// Uncaught SyntaxError: await is only valid in async function

行吧,那咱们把它弄到一个做用域里去。

import sleep from './sleep';

function work() {
    [1, 2, 3].forEach(async v => {
        const rest = await sleep(3);
        console.log(rest);
    });
    return '睡醒了';
}

work();

很差意思,return '睡醒了'没等异步操做完就执行了,这应该也不是你要的效果吧。

因此这种状况,只能用for循环来代替,async和await就能长相厮守了。

import sleep from './sleep';

async function work() {
    const things = [1, 2, 3];
    for (let thing of things) {
        const rest = await sleep(3);
        console.log(rest);
    }
    return '睡醒了';
}

work();

返回Promise实例

有人说async是Generator的语法糖。

naive,朋友们。

async可不止一颗糖哦。它是Generator、co、Promise三者的封装。若是说Generator只是一个状态机的话,那async天生就是为异步而生的。

import sleep from './sleep';

async function work() {
    const needRest = await sleep(6);
    const anotherRest = await sleep(3);
    console.log(needRest);
    console.log(anotherRest);
    return '睡醒了';
}

work().then(res => console.log('?', res), res => console.error('?', res));

由于async函数返回一个Promise实例,那它自己return的值跑哪去了呢?它成了返回的Promise实例resolve时传递的参数。也就是说return '睡醒了'在内部会转成resolve('睡醒了')

我能够保证,返回的是一个真正的Promise实例,因此其余特性向Promise看齐就行了。

并发

也许你发现了,上一节的例子大概要等9秒多才能最终结束执行。但是两个sleep之间并无依赖关系,你跟我说说我凭什么要等9秒多?

以前跟老子说要异步流程控制是否是!如今又跟老子说要并发是否是!

我…知足你。

import sleep from './sleep';

async function work() {
    const needRest = await Promise.all([sleep(6), sleep(3)]);
    console.log(needRest);
    return '睡醒了';
}

work().then(res => console.log('?', res), res => console.error('?', res));
import sleep from './sleep';

async function work() {
    const onePromise = sleep(6);
    const anotherPromise = sleep(3);
    const needRest = await onePromise;
    const anotherRest = await anotherPromise;
    console.log(needRest);
    console.log(anotherRest);
    return '睡醒了';
}

work().then(res => console.log('?', res), res => console.error('?', res));

办法也是有的,还不止一种。手段都差很少,就是把await日后挪,这样既能搂的住,又能实现并发。

大总结

关于异步的知识大致上能够分红两大块:异步机制与异步编程。

异步机制的精髓就是事件循环。

经过控制权反转(从事件通知主线程,到主线程去轮询事件),完美的解决了一个线程忙不过来的问题。

异步编程经历了从回调Promiseasync的伟大探索。异步编程的本质就是用尽量接近同步的语法去处理异步机制。

async目前来看是一种比较完美的同步化异步编程的解决方案。

但其实async是深度集成Promise的,能够说Promiseasync的底层依赖。不只如此,不少API,诸如fetch也是将Promise做为底层依赖的。

因此说一千道一万,异步编程的底色是Promise

Promise是经过什么方式来异步编程的呢?经过then函数,then函数又是经过回调来解决的。

因此呀,回调才是刻在异步编程基因里的东西。你大爷仍是你大爷!

回调换一种说法也叫事件。

这下你理解了为何说JavaScript是事件驱动的吧?
https://github.com/veedrin/ho...

❤️ 看完两件小事

若是你以为这篇文章对你挺有启发,我想请你帮我两个小忙:

把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一块儿进步,一块儿成长!

关注公众号 「IT平头哥联盟」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网 - 前端进阶资源教程 www.javascriptC.com
一个致力于帮助开发者用代码改变世界为使命的平台,天天均可以在这里找到技术世界的头条内容
JS中文网 - 前端进阶资源教程,领略前端前沿,关注IT平头哥联盟
相关文章
相关标签/搜索