成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6中的異步編程:Generators函數(shù)(一)

ztyzz / 2414人閱讀

摘要:由于可以使用語句來暫停異步操作,這讓異步編程的代碼,很像同步數(shù)據(jù)流方法一樣。該臨時函數(shù)就叫做函數(shù)。下面就是簡單的函數(shù)轉(zhuǎn)換器。

訪問原文地址

對ES6的generators的介紹分為3個部分

第一部分base介紹及使用

第二部分基于generators和Promise實現(xiàn)最強大的異步處理邏輯

概述

Generator函數(shù)是協(xié)程在ES6的實現(xiàn),用來做異步流程的封裝,最大特點就是可以交出函數(shù)的執(zhí)行權(quán)(即暫停執(zhí)行)。十分的奇葩,光看語法,簡直認不出這也是JavaScript了。由于可以使用yield語句來暫停異步操作,這讓generators異步編程的代碼,很像同步數(shù)據(jù)流方法一樣。因為從語法角度來看,generators函數(shù)是一個狀態(tài)機,封裝了多個內(nèi)部狀態(tài),通過iterator來分步調(diào)用。

基本語法 2個關(guān)鍵字搞定generators語法

function與函數(shù)名直接的星號:*

函數(shù)體內(nèi)yield語句

function* testGenerator() {
    yield "first yield";
    yield "second yield";
    return "last";
}

var gen = testGenerator();

console.log(gen.next().value);// first yield 
// { value: "first yield", done: false }
console.log(gen.next().value);// second yield
// { value: "second yield", done: false }
console.log(gen.next().value);// last 
// { value: "last", done: true }

console.log(gen.next().value);// undefined
for...of遍歷

for...of循環(huán)可以自動遍歷generators函數(shù)的iterator對象,且不再需要調(diào)用next方法。for...of需要檢查iterator對象的done屬性,如果為true,則結(jié)束循環(huán),因此return語句不能被遍歷到

for (let i of testGenerator) {
    console.log(i);
}
// first yield
// second yield
next方法的參數(shù)

yield句本身沒有返回值,或者說總是返回undefined。next方法可以帶一個參數(shù),該參數(shù)就會被當(dāng)作上一個yield語句的返回值。

function *gen(){
  let arr = [];
  while(true){
    arr.push(yield arr);
  }
}

var name = gen();

console.log(name.next("first").value);//[]
console.log(name.next("second").value);//["second"]
console.log(name.next("thrid").value);//["second","thrid"]

需要注意的是,第一次執(zhí)行next設(shè)置參數(shù)沒有效果。

generators實踐 實現(xiàn)Fibonacci數(shù)列

遞歸實現(xiàn):

function* fib (n, current = 0, next = 1) {
  if (n === 0) {
    return 0;
  }

  yield current;
  yield* fib(n - 1, next, current + next);
}

for (let n of fibonacci()) {
  if (n > 1000) break;
  console.log(n);
}

注:如果存儲計算結(jié)果再過運算,這樣的實現(xiàn)比遞歸方法效率高3倍

function* fibonacci() {
  let [prev, curr] = [0, 1];
  for (;;) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  if (n > 1000) break;
  console.log(n);
}
利用for...of循環(huán),遍歷任意對象(object)的方法

原生的JavaScript對象沒有遍歷接口,無法使用for...of循環(huán),通過Generator函數(shù)為它加上這個接口,就可以用了。

function* objectEntries(obj) {
  let propKeys = Reflect.ownKeys(obj);

  for (let propKey of propKeys) {
    yield [propKey, obj[propKey]];
  }
}

let jane = { first: "Jane", last: "Doe" };

for (let [key, value] of objectEntries(jane)) {
  console.log(`${key}: ${value}`);
}
// first: Jane
// last: Doe
ES6中iterator遍歷接口匯總

for...of循環(huán)

擴展運算符(...)

解構(gòu)賦值

Array.from方法內(nèi)部調(diào)用的

它們都可以將Generator函數(shù)返回的Iterator對象,作為參數(shù)來使用。

function* numbers () {
  yield 1
  yield 2
  return 3
}

// 擴展運算符
[...numbers()] // [1, 2]

// Array.from 方法
Array.from(numbers()) // [1, 2]

// 解構(gòu)賦值
let [x, y] = numbers();
x // 1
y // 2

// for...of 循環(huán)
for (let n of numbers()) {
  console.log(n)
}
// 1
// 2
generators與同步

generators一個特點就是代碼看上去非常像同步編程的效果

function* test() {
    yield( "1st" );
    yield( "2nd" );
    yield( "3rd" );
    yield( "4th" );
}
var iterator = test();

console.log( "== Start of Line ==" );
console.log( iterator.next().value );
console.log( iterator.next().value );
for ( var line of iterator ) {
    console.log( line );
}
console.log( "== End of Line ==" );

看下輸出,濃濃的同步執(zhí)行風(fēng)格。

== Start of Line ==
1st
2nd
3rd
4th
== End of Line ==
callback、Promises、Generators比較

舉例說一個場景,查詢一篇新聞文章的作者信息,流程是:請求最新文章列表->請求某文章相關(guān)id->作者id信息

callback實現(xiàn)
getArticleList(function(articles){
    getArticle(articles[0].id, function(article){
        getAuthor(article.authorId, function(author){
            alert(author.email);
        })
    })
})

function getAuthor(id, callback){
    $.ajax(url,{
        author: id
    }).done(function(result){
        callback(result);
    })
}

function getArticle(id, callback){
    $.ajax(url,{
        id: id
    }).done(function(result){
        callback(result);
    })
}

function getArticleList(callback){
    $.ajax(url)
    .done(function(result){
        callback(result);
    });
}
用Promise來做
getArticleList()
.then(articles => getArticle(articles[0].id))
.then(article => getAuthor(article.authorId))
.then(author => {
    alert(author.email);
});

function getAuthor(id){
    return new Promise(function(resolve, reject){
        $.ajax({
            url: id+"author.json",
            success: function(data) {
              resolve(data);
          }
        })
    });
}

function getArticle(id){
    return new Promise(function(resolve, reject){
        $.ajax({
            url: id+".json",
            success: function(data) {
              resolve(data);
          }
        })
    });
}

function getArticleList(){
    return new Promise(function(resolve, reject){
       $.ajax({
           url: "all.json",
           success: function(data) {
             resolve(data);
         }
       }) 
    });
}
Gererator來實現(xiàn)
function* run(){
  var articles = yield getArticleList();
  var article = yield getArticle(articles[0].id);
  var author = yield getAuthor(article.authorId);
  alert(author.email);  
}

var gen = run();
gen.next().value.then(function(r1){
  gen.next(r1).value.then(function(r2){
      gen.next(r2).value.then(function(r3){
        gen.next(r3);
        console.log("done");
      })
  })
});
runGenerator的實現(xiàn)

每次都要手動去調(diào)用next方法,還是會讓代碼變得冗長,我們可以設(shè)計一個專門用來運行g(shù)enerators的方法,并可以抽象出來,以后就可以做一個統(tǒng)一的error管理,或者獲取本地數(shù)據(jù)邏輯的變化。

Thunk函數(shù)方法

編譯器的‘傳名調(diào)用’實現(xiàn),將所有的參數(shù)放到一個臨時函數(shù)中,再將這個臨時函數(shù)作為參數(shù)傳入到函數(shù)體中。該臨時函數(shù)就叫做Thunk函數(shù)。

任何函數(shù),只要參數(shù)有回調(diào)函數(shù),就能寫成Thunk函數(shù)的方法。下面就是簡單的Thunk函數(shù)轉(zhuǎn)換器。

//es5
var Thunk = function(fn) {
    return function() {
        var args = Array.pototype.silce.call(argumnets);
        return function (callback) {
            args.push(callback);
            return fn.apply(this. args);
        }
    }
}

//es6
var Thunk = function(fn) {
    return function(...args) {
        return function(callback) {
            return fn.call(this, ...args, callback);
        }
    }
}

一個使用Thunk方法來實現(xiàn)readFile的例子

//正常版本的readFile(多參數(shù))
fs.readFile(filename, callback);

//Thunk版本的readFile(單參數(shù))
var readFileThunk = Thunk(filename);
readFileThunk(callback);

var Thunk = function(fileName) {
    return function(callback) {
        return fs.readFile(fileName, callback);
    }
}

可以看到,如果我們通過構(gòu)建一個基于Thunk方法實現(xiàn)的runGenerators函數(shù),可以很好的控制我們的generators運行流程。

function *generator() {
    var articles = yield getArticleList();
    var article = yield getArticle(articles[0].id);
    var author = yield getAuthor(article.authorId);
    console.log(author.email);
}

function runGenerator() {
    var gen = generator();
    
    function go(result) {
        if(result.done) return;
        
        result.value.then(function(rsp) {
            go(gen.next(rsp));
        })
    }
    
    go(gen.next());
}

runGenerator();
參考

[Javascript] Promise, generator, async與ES6

Generator 函數(shù)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80914.html

相關(guān)文章

  • ES6中的異步編程Generators函數(shù)+Promise:最強大的異步處理方式

    摘要:更好的異步編程上面的方法可以適用于那些比較簡單的異步工作流程。小結(jié)的組合目前是最強大,也是最優(yōu)雅的異步流程管理編程方式。 訪問原文地址 generators主要作用就是提供了一種,單線程的,很像同步方法的編程風(fēng)格,方便你把異步實現(xiàn)的那些細節(jié)藏在別處。這讓我們可以用一種很自然的方式書寫我們代碼中的流程和狀態(tài)邏輯,不再需要去遵循那些奇怪的異步編程風(fēng)格。 換句話說,通過將我們generato...

    Taonce 評論0 收藏0
  • JavaScript 異步編程的四種方式

    摘要:異步編程是每個使用編程的人都會遇到的問題,無論是前端的請求,或是的各種異步。本文就來總結(jié)一下常見的四種處理異步編程的方法。利用一種鏈式調(diào)用的方法來組織異步代碼,可以將原來以回調(diào)函數(shù)形式調(diào)用的代碼改為鏈式調(diào)用。 異步編程是每個使用 JavaScript 編程的人都會遇到的問題,無論是前端的 ajax 請求,或是 node 的各種異步 API。本文就來總結(jié)一下常見的四種處理異步編程的方法。...

    microelec 評論0 收藏0
  • ES6 異步編程:Generator

    摘要:生成器是原生提供的異步編程方案,其語法行為和傳統(tǒng)函數(shù)完全不同,阮大的入門一書中對生成器有比較詳盡的介紹,還有一些其他的文章可以參考,比如入門深入淺出三生成器深入淺出十一生成器,續(xù)篇本文主要是通過一些代碼示例來記錄和總結(jié)生成器的用法。 Generator 生成器是es6原生提供的異步編程方案,其語法行為和傳統(tǒng)函數(shù)完全不同,阮大的《ECMAScript 6 入門》一書中對生成器有比較詳盡的...

    Eidesen 評論0 收藏0
  • 如何理解 koa 中間件執(zhí)行機制

    摘要:注是先前版本處理異步函數(shù)的方式,通過可以將異步函數(shù)封裝成,傳入普通參數(shù)后形成僅需要參數(shù)的偏函數(shù),以此簡化調(diào)用代碼目前中的偏函數(shù)已經(jīng)被無情地化了。 前幾天研究了TJ的koa/co4.x和一系列koa依賴的源碼,在知乎上做出了人生首次回答(而且我真得再也不想去知乎回答技術(shù)問題了_(:з」∠)_),因此把文字搬到這里。 ES2015 Generator/Yield 關(guān)于Generator...

    charles_paul 評論0 收藏0
  • 通過ES6 Generator函數(shù)實現(xiàn)異步流程

    摘要:換句話說,我們很好的對代碼的功能關(guān)注點進行了分離通過將使用消費值得地方函數(shù)中的邏輯和通過異步流程來獲取值迭代器的方法進行了有效的分離。但是現(xiàn)在我們通過來管理代碼的異步流程部分,我們解決了回調(diào)函數(shù)所帶來的反轉(zhuǎn)控制等問題。 本文翻譯自 Going Async With ES6 Generators 由于個人能力知識有限,翻譯過程中難免有紕漏和錯誤,還望指正Issue ES6 Gener...

    劉厚水 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<