第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平頭哥聯盟
相關文章
相關標籤/搜索