ES6中文手冊


tags: [ECMAscript]

這是一個 ES2015(ES6) 的Cheatsheet票顾,其中包括提示、小技巧帆调、最佳實踐和一些代碼片段奠骄,幫助你
完成日復(fù)一日的開發(fā)工作。

Table of Contents

var versus let / const

除了 var 以外贷帮,我們現(xiàn)在多了兩個新的標(biāo)識符來聲明變量的存儲戚揭,它們就是 letconst
不同于 var 撵枢,letconst 語句不會造成聲明提升民晒。

一個 var 的例子:

var snack = 'Meow Mix';

function getFood(food) {
    if (food) {
        var snack = 'Friskies';
        return snack;
    }
    return snack;
}

getFood(false); // undefined

讓我們再觀察下面語句中,使用 let 替換了 var 后的表現(xiàn):

let snack = 'Meow Mix';

function getFood(food) {
    if (food) {
        let snack = 'Friskies';
        return snack;
    }
    return snack;
}

getFood(false); // 'Meow Mix'

當(dāng)我們重構(gòu)使用 var 的老代碼時锄禽,一定要注意這種變化潜必。盲目使用 let 替換 var 后可能會導(dǎo)致預(yù)期意外的結(jié)果。

注意letconst 是塊級作用域語句沃但。所以在語句塊以外引用這些變量時磁滚,會造成引用錯誤 ReferenceError

console.log(x);

let x = 'hi'; // ReferenceError: x is not defined

最佳實踐: 在重構(gòu)老代碼時宵晚,var 聲明需要格外的注意垂攘。在創(chuàng)建一個新項目時,使用 let 聲明一個變量淤刃,使用 const 來聲明一個不可改變的常量晒他。

(回到目錄)

Replacing IIFEs with Blocks

我們以往創(chuàng)建一個 立即執(zhí)行函數(shù) 時,一般是在函數(shù)最外層包裹一層括號逸贾。
ES6支持塊級作用域(更貼近其他語言)陨仅,我們現(xiàn)在可以通過創(chuàng)建一個代碼塊(Block)來實現(xiàn),不必通過創(chuàng)建一個函數(shù)來實現(xiàn)铝侵,

(function () {
    var food = 'Meow Mix';
}());

console.log(food); // Reference Error

使用支持塊級作用域的ES6的版本:

{
    let food = 'Meow Mix';
}

console.log(food); // Reference Error

(回到目錄)

Arrow Functions

一些時候灼伤,我們在函數(shù)嵌套中需要訪問上下文中的 this。比如下面的例子:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(function (character) {
        return this.name + character; // Cannot read property 'name' of undefined
    });
};

一種通用的方式是把上下文中的 this 保存在一個變量里:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    var that = this; // Store the context of this
    return arr.map(function (character) {
        return that.name + character;
    });
};

我們也可以把 this 通過屬性傳進(jìn)去:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(function (character) {
        return this.name + character;
    }, this);
};

還可以直接使用 bind

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(function (character) {
        return this.name + character;
    }.bind(this));
};

使用 箭頭函數(shù)咪鲜,this 的值不用我們再做如上幾段代碼的特殊處理狐赡,直接使用即可。
上面的代碼可以重寫為下面這樣:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(character => this.name + character);
};

最佳實踐:使用箭頭函數(shù)嗜诀,再也不用考慮 this 的問題了猾警。

當(dāng)我們編寫只返回一個表達(dá)式值的簡單函數(shù)時孔祸,也可以使用箭頭函數(shù),如下:

var squares = arr.map(function (x) { return x * x }); // Function Expression
const arr = [1, 2, 3, 4, 5];
const squares = arr.map(x => x * x); // Arrow Function for terser implementation

最佳實踐:盡可能地多使用 箭頭函數(shù)发皿。

(回到目錄)

Strings

在ES6中崔慧,標(biāo)準(zhǔn)庫也被同樣增強了,像字符串對象就新增了 .includes().repeat() 方法穴墅。

.includes( )

var string = 'food';
var substring = 'foo';

console.log(string.indexOf(substring) > -1);

現(xiàn)在惶室,我們可以使用 .inclues() 方法,替代以往判斷內(nèi)容 > -1 的方式玄货。
.includes() 方法會極簡地返回一個布爾值結(jié)果皇钞。

const string = 'food';
const substring = 'foo';

console.log(string.includes(substring)); // true

.repeat( )

function repeat(string, count) {
    var strings = [];
    while(strings.length < count) {
        strings.push(string);
    }
    return strings.join('');
}

在ES6中,我們可以使用一個極簡的方法來實現(xiàn)重復(fù)字符:

// String.repeat(numberOfRepetitions)
'meow'.repeat(3); // 'meowmeowmeow'

Template Literals

使用 字符串模板字面量松捉,我可以在字符串中直接使用特殊字符夹界,而不用轉(zhuǎn)義。

var text = "This string contains \"double quotes\" which are escaped.";
let text = `This string contains "double quotes" which don't need to be escaped anymore.`;

字符串模板字面量 還支持直接插入變量隘世,可以實現(xiàn)字符串與變量的直接連接輸出可柿。

var name = 'Tiger';
var age = 13;

console.log('My cat is named ' + name + ' and is ' + age + ' years old.');

更簡單的版本:

const name = 'Tiger';
const age = 13;

console.log(`My cat is named ${name} and is ${age} years old.`);

ES5中,我們要這樣生成多行文本:

var text = (
    'cat\n' +
    'dog\n' +
    'nickelodeon'
);

或者:

var text = [
    'cat',
    'dog',
    'nickelodeon'
].join('\n');

字符串模板字面量 讓我們不必特別關(guān)注多行字符串中的換行轉(zhuǎn)義符號丙者,直接換行即可:

let text = ( `cat
dog
nickelodeon`
);

字符串模板字面量 內(nèi)部可以使用表達(dá)式复斥,像這樣:

let today = new Date();
let text = `The time and date is ${today.toLocaleString()}`;

(回到目錄)

Destructuring

解構(gòu)讓我們可以使用非常便捷的語法,直接將數(shù)組或者對象中的值直接分別導(dǎo)出到多個變量中械媒,

Destructuring Arrays

解構(gòu)數(shù)組

var arr = [1, 2, 3, 4];
var a = arr[0];
var b = arr[1];
var c = arr[2];
var d = arr[3];
let [a, b, c, d] = [1, 2, 3, 4];

console.log(a); // 1
console.log(b); // 2

Destructuring Objects

解構(gòu)對象

var luke = { occupation: 'jedi', father: 'anakin' };
var occupation = luke.occupation; // 'jedi'
var father = luke.father; // 'anakin'
let luke = { occupation: 'jedi', father: 'anakin' };
let {occupation, father} = luke;

console.log(occupation); // 'jedi'
console.log(father); // 'anakin'

(回到目錄)

Modules

ES6之前目锭,瀏覽器端的模塊化代碼,我們使用像Browserify這樣的庫纷捞,
Node.js 中痢虹,我們則使用 require
在ES6中主儡,我們現(xiàn)在可以直接使用AMD 和 CommonJS這些模塊了世分。

Exporting in CommonJS

module.exports = 1;
module.exports = { foo: 'bar' };
module.exports = ['foo', 'bar'];
module.exports = function bar () {};

Exporting in ES6

在ES6中,提供了多種設(shè)置模塊出口的方式缀辩,比如我們要導(dǎo)出一個變量,那么使用 變量名

export let name = 'David';
export let age  = 25;??

還可以為對象 導(dǎo)出一個列表

function sumTwo(a, b) {
    return a + b;
}

function sumThree(a, b, c) {
    return a + b + c;
}

export { sumTwo, sumThree };

我們也可以使用簡單的一個 export 關(guān)鍵字來導(dǎo)出一個結(jié)果值:

export function sumTwo(a, b) {
    return a + b;
}

export function sumThree(a, b, c) {
    return a + b + c;
}

最后踪央,我們可以 導(dǎo)出一個默認(rèn)出口

function sumTwo(a, b) {
    return a + b;
}

function sumThree(a, b, c) {
    return a + b + c;
}

let api = {
    sumTwo,
    sumThree
};

export default api;

最佳實踐:總是在模塊的 最后 使用 export default 方法臀玄。
它讓模塊的出口更清晰明了,節(jié)省了閱讀整個模塊來尋找出口的時間畅蹂。
更多的是健无,在大量CommonJS模塊中,通用的習(xí)慣是設(shè)置一個出口值或者出口對象液斜。
最受這個規(guī)則累贤,可以讓我們的代碼更易讀叠穆,且更方便的聯(lián)合使用CommonJS和ES6模塊。

Importing in ES6

ES6提供了好幾種模塊的導(dǎo)入方式臼膏。我們可以單獨引入一個文件:

import 'underscore';

這里需要注意的是硼被, 整個文件的引入方式會執(zhí)行該文件內(nèi)的最上層代碼

就像Python一樣渗磅,我們還可以命名引用:

import { sumTwo, sumThree } from 'math/addition';

我們甚至可以使用 as 給這些模塊重命名:

import {
    sumTwo as addTwoNumbers,
    sumThree as sumThreeNumbers
} from 'math/addition';

另外嚷硫,我們能 引入所有的東西(原文:import all the things) (也稱為命名空間引入)

import * as util from 'math/addition';

最后,我們能可以從一個模塊的眾多值中引入一個列表:

import * as additionUtil from 'math/addtion';
const { sumTwo, sumThree } = additionUtil;

像這樣引用默認(rèn)對象:

import api from 'math/addition';
// Same as: import { default as api } from 'math/addition';

我們建議一個模塊導(dǎo)出的值應(yīng)該越簡潔越好始鱼,不過有時候有必要的話命名引用和默認(rèn)引用可以混著用仔掸。如果一個模塊是這樣導(dǎo)出的:

// foos.js
export { foo as default, foo1, foo2 };

那我們可以如此導(dǎo)入這個模塊的值:

import foo, { foo1, foo2 } from 'foos';

我們還可以導(dǎo)入commonjs模塊,例如React:

import React from 'react';
const { Component, PropTypes } = React;

更簡化版本:

import React, { Component, PropTypes } from 'react';

注意:被導(dǎo)出的值是被 綁定的(原文:bingdings)医清,而不是引用起暮。
所以,改變一個模塊中的值的話会烙,會影響其他引用本模塊的代碼负懦,一定要避免此種改動發(fā)生。

(回到目錄)

Parameters

在ES5中持搜,許多種方法來處理函數(shù)的 參數(shù)默認(rèn)值(default values)密似,參數(shù)數(shù)量(indefinite arguments)參數(shù)命名(named parameters)葫盼。
ES6中残腌,我們可以使用非常簡潔的語法來處理上面提到的集中情況。

Default Parameters

function addTwoNumbers(x, y) {
    x = x || 0;
    y = y || 0;
    return x + y;
}

ES6中贫导,我們可以簡單為函數(shù)參數(shù)啟用默認(rèn)值:

function addTwoNumbers(x=0, y=0) {
    return x + y;
}
addTwoNumbers(2, 4); // 6
addTwoNumbers(2); // 2
addTwoNumbers(); // 0

Rest Parameters

ES5中抛猫,遇到參數(shù)數(shù)量不確定時,我們只能如此處理:

function logArguments() {
    for (var i=0; i < arguments.length; i++) {
        console.log(arguments[i]);
    }
}

使用 rest 操作符孩灯,我們可以給函數(shù)傳入一個不確定數(shù)量的參數(shù)列表:

function logArguments(...args) {
    for (let arg of args) {
        console.log(arg);
    }
}

Named Parameters

命名函數(shù)
ES5中闺金,當(dāng)我們要處理多個 命名參數(shù) 時,通常會傳入一個 選項對象 的方式峰档,這種方式被jQuery采用败匹。

function initializeCanvas(options) {
    var height = options.height || 600;
    var width  = options.width  || 400;
    var lineStroke = options.lineStroke || 'black';
}

我們可以利用上面提到的新特性 解構(gòu) ,來完成與上面同樣功能的函數(shù):
We can achieve the same functionality using destructuring as a formal parameter
to a function:

function initializeCanvas(
    { height=600, width=400, lineStroke='black'}) {
        // ...
    }
    // Use variables height, width, lineStroke here

如果我們需要把這個參數(shù)變?yōu)榭蛇x的讥巡,那么只要把該參數(shù)解構(gòu)為一個空對象就好了:

function initializeCanvas(
    { height=600, width=400, lineStroke='black'} = {}) {
        // ...
    }

Spread Operator

我們可以利用展開操作符(Spread Operator)來把一組數(shù)組的值掀亩,當(dāng)作參數(shù)傳入:

Math.max(...[-1, 100, 9001, -32]); // 9001

(回到目錄)

Classes

在ES6以前,我們實現(xiàn)一個類的功能的話欢顷,需要首先創(chuàng)建一個構(gòu)造函數(shù)槽棍,然后擴展這個函數(shù)的原型方法,就像這樣:

function Person(name, age, gender) {
    this.name   = name;
    this.age    = age;
    this.gender = gender;
}

Person.prototype.incrementAge = function () {
    return this.age += 1;
};

繼承父類的子類需要這樣:

function Personal(name, age, gender, occupation, hobby) {
    Person.call(this, name, age, gender);
    this.occupation = occupation;
    this.hobby = hobby;
}

Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
    return Person.prototype.incrementAge.call(this) += 20;
};

ES6提供了一些語法糖來實現(xiàn)上面的功能,我們可以直接創(chuàng)建一個類:

class Person {
    constructor(name, age, gender) {
        this.name   = name;
        this.age    = age;
        this.gender = gender;
    }

    incrementAge() {
      this.age += 1;
    }
}

繼承父類的子類只要簡單的使用 extends 關(guān)鍵字就可以了:

class Personal extends Person {
    constructor(name, age, gender, occupation, hobby) {
        super(name, age, gender);
        this.occupation = occupation;
        this.hobby = hobby;
    }

    incrementAge() {
        super.incrementAge();
        this.age += 20;
        console.log(this.age);
    }
}

最佳實踐:ES6新的類語法把我們從晦澀難懂的實現(xiàn)和原型操作中解救出來炼七,這是個非常適合初學(xué)者的功能缆巧,而且能讓我們寫出更干凈整潔的代碼。

(回到目錄)

Symbols

符號(Symbols)在ES6版本之前就已經(jīng)存在了豌拙,但現(xiàn)在我們擁有一個公共的接口來直接使用它們陕悬。
Symbols對象是一旦創(chuàng)建就不可以被更改的(immutable)而且能被用做hash數(shù)據(jù)類型中的鍵。

Symbol( )

調(diào)用 Symbol() 或者 Symbol(描述文本) 會創(chuàng)建一個唯一的姆蘸、在全局中不可以訪問的符號對象墩莫。
一個 Symbol() 的應(yīng)用場景是:在自己的項目中使用第三方代碼庫,且你需要給他們的對象或者命名空間打補丁代碼逞敷,又不想改動或升級第三方原有代碼的時候狂秦。
舉個例子,如果你想給 React.Component 這個類添加一個 refreshComponent 方法推捐,但又確定不了這個方法會不會在下個版本中加入裂问,你可以這么做:

const refreshComponent = Symbol();

React.Component.prototype[refreshComponent] = () => {
    // do something
}

Symbol.for(key)

使用 Symbol.for(key) 也是會創(chuàng)建一個不可改變的Symbol對象,但區(qū)別于上面的創(chuàng)建方法牛柒,這個對象是在全局中可以被訪問到的堪簿。
調(diào)用兩次 Symbol.for(key) 會返回相同的Symbol實例。

提示:這并不同于 Symbol(description)皮壁。

Symbol('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol.for('foo') // true

一個Symbols常用的使用場景椭更,是需要使用特別 Symbol.for(key) 方法來實現(xiàn)代碼間的協(xié)作。
這能讓你在你的代碼中蛾魄,查找包含已知的接口的第三方代碼中Symbol成員虑瀑。(譯者:這句話好難翻。滴须。舌狗。原文:This can be
achieved by having your code look for a Symbol member on object arguments from third parties that contain some known interface. )舉個例子:

function reader(obj) {
    const specialRead = Symbol.for('specialRead');
    if (obj[specialRead]) {
        const reader = obj[specialRead]();
        // do something with reader
    } else {
        throw new TypeError('object cannot be read');
    }
}

之后在另一個庫中:

const specialRead = Symbol.for('specialRead');

class SomeReadableType {
    [specialRead]() {
        const reader = createSomeReaderFrom(this);
        return reader;
    }
}

注意Symbol.iterable 在ES6中像其他可枚舉的對象,如數(shù)組扔水,字符串痛侍,generators一樣,當(dāng)這個方法被調(diào)用時會激活一個枚舉器并返回一個對象魔市。

(回到目錄)

Maps

Maps 是一個Javascript中很重要(迫切需要)的數(shù)據(jù)結(jié)構(gòu)主届。
在ES6之前,我們創(chuàng)建一個 hash 通常是使用一個對象:

var map = new Object();
map[key1] = 'value1';
map[key2] = 'value2';

但是待德,這樣的代碼無法避免函數(shù)被特別的屬性名覆蓋的意外情況:

> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');
> TypeError: Property 'hasOwnProperty' is not a function

Maps 讓我們使用 set岂膳,getsearch 操作數(shù)據(jù)。

let map = new Map();
> map.set('name', 'david');
> map.get('name'); // david
> map.has('name'); // true

Maps最強大的地方在于我們不必只能使用字符串來做key了磅网,現(xiàn)在可以使用任何類型來當(dāng)作key,而且key不會被強制類型轉(zhuǎn)換為字符串筷屡。

let map = new Map([
    ['name', 'david'],
    [true, 'false'],
    [1, 'one'],
    [{}, 'object'],
    [function () {}, 'function']
]);

for (let key of map.keys()) {
    console.log(typeof key);
    // > string, boolean, number, object, function
}

提示:當(dāng)使用 map.get() 判斷值是否相等時涧偷,非基礎(chǔ)類型比如一個函數(shù)或者對象簸喂,將不會正常工作。
有鑒于此燎潮,還是建議使用字符串喻鳄,布爾和數(shù)字類型的數(shù)據(jù)類型。

我們還可以使用 .entries() 方法來遍歷整個map對象:

for (let [key, value] of map.entries()) {
    console.log(key, value);
}

(回到目錄)

WeakMaps

在ES5之前的版本确封,我們?yōu)榱舜鎯λ接袛?shù)據(jù)除呵,有好幾種方法。像使用這種下劃線命名約定:

class Person {
    constructor(age) {
        this._age = age;
    }

    _incrementAge() {
        this._age += 1;
    }
}

在一個開源項目中爪喘,命名規(guī)則很難維持得一直很好颜曾,這樣經(jīng)常會造成一些困擾。
此時秉剑,我們可以選擇使用WeakMaps來替代Maps來存儲我們的數(shù)據(jù):

let _age = new WeakMap();
class Person {
    constructor(age) {
        _age.set(this, age);
    }

    incrementAge() {
        let age = _age.get(this) + 1;
        _age.set(this, age);
        if (age > 50) {
            console.log('Midlife crisis');
        }
    }
}

使用WeakMaps來保存我們私有數(shù)據(jù)的理由之一是不會暴露出屬性名泛豪,就像下面的例子中的 Reflect.ownKeys()

> const person = new Person(50);
> person.incrementAge(); // 'Midlife crisis'
> Reflect.ownKeys(person); // []

一個使用WeakMaps存儲數(shù)據(jù)更實際的例子,就是有關(guān)于一個DOM元素和對該DOM元素(有污染)地操作:

let map = new WeakMap();
let el  = document.getElementById('someElement');

// Store a weak reference to the element with a key
map.set(el, 'reference');

// Access the value of the element
let value = map.get(el); // 'reference'

// Remove the reference
el.parentNode.removeChild(el);
el = null;

value = map.get(el); // undefined

上面的例子中侦鹏,一個對象被垃圾回收期給銷毀了诡曙,WeakMaps會自動的把自己內(nèi)部所對應(yīng)的鍵值對數(shù)據(jù)同時銷毀。

提示:結(jié)合這個例子略水,再考慮下jQuery是如何實現(xiàn)緩存帶有引用的DOM元素這個功能的价卤,使用了WeakMaps的話,當(dāng)被緩存的DOM元素被移除的時渊涝,jQuery可以自動釋放相應(yīng)元素的內(nèi)存慎璧。
通常情況下,在涉及DOM元素存儲和緩存的情況下驶赏,使用WeakMaps是非常適合的炸卑。

(回到目錄)

Promises

Promises讓我們讓我們多縮進(jìn)難看的代碼(回調(diào)地獄):

func1(function (value1) {
    func2(value1, function (value2) {
        func3(value2, function (value3) {
            func4(value3, function (value4) {
                func5(value4, function (value5) {
                    // Do something with value 5
                });
            });
        });
    });
});

寫成這樣:

func1(value1)
    .then(func2)
    .then(func3)
    .then(func4)
    .then(func5, value5 => {
        // Do something with value 5
    });

在ES6之前,我們使用bluebird 或者
Q∶喊現(xiàn)在我們有了原生版本的 Promises:

new Promise((resolve, reject) =>
    reject(new Error('Failed to fulfill Promise')))
        .catch(reason => console.log(reason));

這里有兩個處理函數(shù)盖文,resolve(當(dāng)Promise執(zhí)行成功完畢時調(diào)用的回調(diào)函數(shù)) 和 reject (當(dāng)Promise執(zhí)行不接受時調(diào)用的回調(diào)函數(shù))

Promises的好處:大量嵌套錯誤回調(diào)函數(shù)會使代碼變得難以閱讀理解。
使用了Promises蚯姆,我們可以讓我們代碼變得更易讀五续,組織起來更合理。
此外龄恋,Promise處理后的值疙驾,無論是解決還是拒絕的結(jié)果值,都是不可改變的郭毕。

下面是一些使用Promises的實際例子:

var fetchJSON = function(url) {
    return new Promise((resolve, reject) => {
        $.getJSON(url)
            .done((json) => resolve(json))
            .fail((xhr, status, err) => reject(status + err.message));
    });
};

我們還可以使用 Promise.all() 來異步的 并行 處理一個數(shù)組的數(shù)據(jù)它碎。

var urls = [
    'http://www.api.com/items/1234',
    'http://www.api.com/items/4567'
];

var urlPromises = urls.map(fetchJSON);

Promise.all(urlPromises)
    .then(function (results) {
        results.forEach(function (data) {
        });
    })
    .catch(function (err) {
        console.log('Failed: ', err);
    });

(回到目錄)

Generators

就像Promises如何讓我們避免回調(diào)地獄一樣,Generators也可以使我們的代碼扁平化,同時給予我們開發(fā)者像開發(fā)同步代碼一樣的感覺來寫異步代碼扳肛。Generators本質(zhì)上是一種支持的函數(shù)傻挂,隨后返回表達(dá)式的值。
Generators實際上是支持暫停運行挖息,隨后根據(jù)上一步的返回值再繼續(xù)運行的一種函數(shù)金拒。

下面代碼是一個使用generators函數(shù)的簡單例子:

function* sillyGenerator() {
    yield 1;
    yield 2;
    yield 3;
    yield 4;
}

var generator = sillyGenerator();
> console.log(generator.next()); // { value: 1, done: false }
> console.log(generator.next()); // { value: 2, done: false }
> console.log(generator.next()); // { value: 3, done: false }
> console.log(generator.next()); // { value: 4, done: false }

就像上面的例子,當(dāng)next運行時套腹,它會把我們的generator向前“推動”绪抛,同時執(zhí)行新的表達(dá)式。
我們能利用Generators來像書寫同步代碼一樣書寫異步代碼电禀。

// Hiding asynchronousity with Generators

function request(url) {
    getJSON(url, function(response) {
        generator.next(response);
    });
}

這里我們寫個generator函數(shù)將要返回我們的數(shù)據(jù):

function* getData() {
    var entry1 = yield request('http://some_api/item1');
    var data1  = JSON.parse(entry1);
    var entry2 = yield request('http://some_api/item2');
    var data2  = JSON.parse(entry2);
}

借助于 yield幢码,我們可以保證 entry1 確實拿到數(shù)據(jù)并轉(zhuǎn)換后再賦值給 data1

當(dāng)我們使用generators來像書寫同步代碼一樣書寫我們的異步代碼邏輯時鞭呕,沒有一種清晰簡單的方式來處理期間可能會產(chǎn)生的錯誤或者異常蛤育。在這種情況下,我們可以在我們的generator中引入Promises來處理葫松,就像下面這樣:

function request(url) {
    return new Promise((resolve, reject) => {
        getJSON(url, resolve);
    });
}

我們再寫一個函數(shù)瓦糕,其中使用 next 來步進(jìn)我們的generator的同事,再利用我們上面的 request 方法來產(chǎn)生(yield)一個Promise腋么。

function iterateGenerator(gen) {
    var generator = gen();
    var ret;
    (function iterate(val) {
        ret = generator.next();
        if(!ret.done) {
            ret.value.then(iterate);
        }
    })();
}

在Generator中引入了Promises后咕娄,我們就可以通過Promise的 .catchreject 來捕捉和處理錯誤了。
使用了我們新版的Generator后珊擂,新版的調(diào)用就像老版本一樣簡單可讀(譯者注:有微調(diào)):

iterateGenerator(function* getData() {
    var entry1 = yield request('http://some_api/item1');
    var data1  = JSON.parse(entry1);
    var entry2 = yield request('http://some_api/item2');
    var data2  = JSON.parse(entry2);
});

在使用Generator后圣勒,我們可以重用我們的老版本代碼實現(xiàn),以此展示了Generator的力量摧扇。
當(dāng)使用Generators和Promises后圣贸,我們可以像書寫同步代碼一樣書寫異步代碼的同時優(yōu)雅地解決了錯誤處理問題。
此后扛稽,我們實際上可以開始利用更簡單的一種方式了吁峻,它就是async-await

(回到目錄)

Async Await

async await 隨著ES2016版本就要發(fā)布了在张,它給我們提供了一種更輕松的用含、更簡單的可以替代的實現(xiàn)上面 Generators 配合 Promises 組合代碼的一種編碼方式,讓我們來看看例子:

var request = require('request');

function getJSON(url) {
  return new Promise(function(resolve, reject) {
    request(url, function(error, response, body) {
      resolve(body);
    });
  });
}

async function main() {
  var data = await getJSON();
  console.log(data); // NOT undefined!
}

main();

它們看上去和Generators很像帮匾。我(作者)強烈推薦使用 async await 來替代Generators + Promises的寫法啄骇。
這里是個很好的學(xué)習(xí)資源,讓我們學(xué)習(xí)和使用這項ES7中的新功能瘟斜。

(回到目錄)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缸夹,一起剝皮案震驚了整個濱河市痪寻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌明未,老刑警劉巖槽华,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趟妥,居然都是意外死亡,警方通過查閱死者的電腦和手機佣蓉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門披摄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人勇凭,你說我怎么就攤上這事疚膊。” “怎么了虾标?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵寓盗,是天一觀的道長。 經(jīng)常有香客問我璧函,道長傀蚌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任蘸吓,我火速辦了婚禮善炫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘库继。我一直安慰自己箩艺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布宪萄。 她就那樣靜靜地躺著艺谆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拜英。 梳的紋絲不亂的頭發(fā)上静汤,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音聊记,去河邊找鬼撒妈。 笑死,一個胖子當(dāng)著我的面吹牛排监,可吹牛的內(nèi)容都是我干的狰右。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼舆床,長吁一口氣:“原來是場噩夢啊……” “哼棋蚌!你這毒婦竟也來了嫁佳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谷暮,失蹤者是張志新(化名)和其女友劉穎蒿往,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湿弦,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡瓤漏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了颊埃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔬充。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖班利,靈堂內(nèi)的尸體忽然破棺而出饥漫,到底是詐尸還是另有隱情,我是刑警寧澤罗标,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布庸队,位于F島的核電站,受9級特大地震影響闯割,放射性物質(zhì)發(fā)生泄漏彻消。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一纽谒、第九天 我趴在偏房一處隱蔽的房頂上張望证膨。 院中可真熱鬧,春花似錦鼓黔、人聲如沸央勒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崔步。三九已至,卻和暖如春缎谷,著一層夾襖步出監(jiān)牢的瞬間井濒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工列林, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瑞你,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓希痴,卻偏偏與公主長得像者甲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子砌创,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容