體驗異步的終極解決方案-ES7的Async/Await

第一個例子


Async/Await應該是目前最簡單的異步方案了,首先來看個例子。node

這裏咱們要實現一個暫停功能,輸入N毫秒,則停頓N毫秒後才繼續往下執行。git

var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, time);
    })
};

var start = async function () {
    // 在這裏使用起來就像同步代碼那樣直觀
    console.log('start');
    await sleep(3000);
    console.log('end');
};

start();

控制檯先輸出start,稍等3秒後,輸出了endes6

 

基本規則


 

  1. async 表示這是一個async函數await只能用在這個函數裏面github

  2. await 表示在這裏等待promise返回結果了,再繼續執行。編程

  3. await 後面跟着的應該是一個promise對象(固然,其餘返回值也不要緊,只是會當即執行,不過那樣就沒有意義了…)json

得到返回值


 

await等待的雖然是promise對象,但沒必要寫.then(..),直接能夠獲得返回值。api

 1 var sleep = function (time) {
 2     return new Promise(function (resolve, reject) {
 3         setTimeout(function () {
 4             // 返回 ‘ok’
 5             resolve('ok');
 6         }, time);
 7     })
 8 };
 9 
10 var start = async function () {
11     let result = await sleep(3000);
12     console.log(result); // 收到 ‘ok’
13 };

 

 

捕捉錯誤


 

 

既然.then(..)不用寫了,那麼.catch(..)也不用寫,能夠直接用標準的try catch語法捕捉錯誤。promise

var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            // 模擬出錯了,返回 ‘error’
            reject('error');
        }, time);
    })
};

var start = async function () {
    try {
        console.log('start');
        await sleep(3000); // 這裏獲得了一個返回錯誤
        
        // 因此如下代碼不會被執行了
        console.log('end');
    } catch (err) {
        console.log(err); // 這裏捕捉到錯誤 `error`
    }
};

 

 

 

 

循環多個await


 

await看起來就像是同步代碼,因此能夠理所固然的寫在for循環裏,沒必要擔憂以往須要閉包才能解決的問題。閉包

..省略以上代碼

var start = async function () {
    for (var i = 1; i <= 10; i++) {
        console.log(`當前是第${i}次等待..`);
        await sleep(1000);
    }
};

值得注意的是,await必須在async函數的上下文中的。異步

..省略以上代碼

let 一到十 = [1,2,3,4,5,6,7,8,9,10];

// 錯誤示範
一到十.forEach(function (v) {
    console.log(`當前是第${v}次等待..`);
    await sleep(1000); // 錯誤!! await只能在async函數中運行
});

// 正確示範
for(var v of 一到十) {
    console.log(`當前是第${v}次等待..`);
    await sleep(1000); // 正確, for循環的上下文還在async函數中
}

 

 

 

 

 

第二個例子


 

這個例子是一個小應用,根據電影文件名,自動下載對應的海報。直接貼出代碼,就不說明了。

 

import fs from 'fs';
import path from 'path';
import request from 'request';

var movieDir = __dirname + '/movies',
    exts     = ['.mkv', '.avi', '.mp4', '.rm', '.rmvb', '.wmv'];

// 讀取文件列表
var readFiles = function () {
    return new Promise(function (resolve, reject) {
        fs.readdir(movieDir, function (err, files) {
            resolve(files.filter((v) => exts.includes(path.parse(v).ext)));
        });
    });
};

// 獲取海報
var getPoster = function (movieName) {
    let url = `https://api.douban.com/v2/movie/search?q=${encodeURI(movieName)}`;

    return new Promise(function (resolve, reject) {
        request({url: url, json: true}, function (error, response, body) {
            if (error) return reject(error);

            resolve(body.subjects[0].images.large);
        })
    });
};

// 保存海報
var savePoster = function (movieName, url) {
    request.get(url).pipe(fs.createWriteStream(path.join(movieDir, movieName + '.jpg')));
};


(async () => {
    let files = await readFiles();

    // await只能使用在原生語法
    for (var file of files) {
        let name = path.parse(file).name;

        console.log(`正在獲取【${name}】的海報`);
        savePoster(name, await getPoster(name));
    }

    console.log('=== 獲取海報完成 ===');
})();

 

 

文中講到的例子的源代碼 https://github.com/think2011/ES7-Async-Await-Demo

很詳細的異步編程教程 http://es6.ruanyifeng.com/#docs/async

很詳細的promise小書 http://liubin.github.io/promises-book/#introduction

 

 

轉載自:http://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6

相關文章
相關標籤/搜索