js異步之async和await實現同步寫法

首先我們假設有一方法 readFile 可以讀取文件內容,  但是它是異步的。

var gen = function* (){
    var a = yield readFile('./a.txt');
    console.log(a.toString());
    var b = yield readFile('./b.txt');
    console.log(b.toString());
};

首先我們看下上面的代碼,如果我們將function 後面的 * 改成 async,將yield 改成 await,也就是下面的代碼

var gen = function async (){
    var a = await readFile('./a.txt');
    console.log(a.toString());
    var b = await readFile('./b.txt');
    console.log(b.toString());
};

是不是就是我們想要的同步寫異步操作瞭,第一種寫法就是 es6 中新支持的特性,Generator 函數,那什麼是 Generator 函數呢,簡單來說Generator 函數有多種理解角度。語法上,首先可以把它理解成,Generator 函數是一個狀態機,封裝瞭多個內部狀態。執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator 函數除瞭狀態機,還是一個遍歷器對象生成函數。返回的遍歷器對象,可以依次遍歷 Generator 函數內部的每一個狀態。上面的官方解釋看不懂沒關系。我們下面用例子演示下。

function* func(){ 
    console.log("one"); 
    yield '1'; 
    console.log("two"); 
    yield '2'; 
    console.log("three"); 
    return '3'; 
}
var f = func();
f.next(); // one // {value: "1", done: false} 
f.next(); // two // {value: "2", done: false} 
f.next(); // three // {value: "3", done: true} 
f.next(); // {value: undefined, done: true}

上面的代碼我們第一次調用 f.next() 時,函數 func 開始執行,並在執行到第一個 yield 時停住,並返回 yield 後面表達式的值,格式就是 {value: "1", done: false}  這種格式,value就是 yield 表達式的值
done 表示func函數是否執行完畢,此時如果我們如果接著調用 f.next(),類推將返回第二 yield 後面表達式的值,也就是 {value: "2", done: false}。我們可以繼續調用 f.next() 直至 done 變成 true, 它表示func函數執行完瞭。

function* func(){
    var a = yield '1';
    console.log(a);
    var b = yield '2';
    console.log(b);
}
var f = func();
f.next(); 
f.next('1'); 

f.next('2');我們繼續改造 func 函數為上面這種,在 next 分別傳入 1 和 2,我們會發現 console.log(a) 打印 1 ,console.log(b) 打印 2,也就是我們可以傳值到 Generator 函數中。
現在我們回到下面這段代碼上面來,然後重新設計下,並實現  readFile 函數。

var gen = function* (){
    var a = yield readFile('./a.txt');
    console.log(a.toString());
    var b = yield readFile('./b.txt');
    console.log(b.toString());
};

var readFile = function (fileName){
    return new Promise((resolve)=>{
        fs.readFile(fileName, (err, data)=>{
            resolve(data);
        })
    });
};

function run(fn) {
    var gen = fn();
    function next(data) {
        var result = gen.next(data);
        if (result.done) return;
        result.value.then((data)=>{
            next(data);
        })
    }
    next();
}

run(gen);

看上面的代碼我們用 promise  實現  readFile 函數,此時我們 yield 的返回值就是一個 promise 對象瞭,我們就可以使用, result.value.then((data)=>{next(data);})將 yield 返回的 value 值重新傳回 Generator 函數,這樣我們的 console.log(a.toString()); 就可以獲取到 a.txt 文件中的內容瞭, if (result.done) return; 可以用瞭判斷 Generator 函數 是否已執行完畢,用來結束循環調用。所以如果我們單獨去看 gen 函數,是不是就是將異步操作寫成同步語法瞭,如果我們將function 後面的 * 改成 async,將yield 改成 await也就是我們常用語法瞭。

到此這篇關於js異步之async和await實現同步寫法的文章就介紹到這瞭,更多相關js async和await同步內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: