先吐槽一件事,最近把原先的 TOP 域名更換到 CN 域名,而且用 Gatsby
重建我的站點,以前是用採用 HTTPS 部署的方式繞過阿里雲的域名備案系統。更換 CN 域名後,這招無論用了,😭😭 域名必需要備案了,等待幕布郵寄中……node
有人要問了,都 9102 年,ES10 都出來了,怎麼還在講 ES6,非也!本文針對 ES6 幾個鮮爲人知、和重要的特性作講解,精彩的在後面!es6
ES6 除了固有的函數做用域,還引入了塊級做用域({})面試
function f() {
{
let x; // ①
{
// 包含在當前塊中,與 ① 中的 x 分屬不一樣做用域
const x = "sneaky";
// 錯誤,const 定義的變量不能夠從新賦值,若是 const 定義了一個對象,那麼對象的屬性是能夠修改的
x = "foo";
}
// let 定義的變量能夠從新賦值
x = "bar";
// 錯誤,x 在 ① 塊中已被定義
let x = "inner";
}
}
複製代碼
function f(x, y=12) {
// y 等於 12 若是不傳遞 (或者傳遞 undefined)
return x + y;
}
f(3); // 15
複製代碼
function f(x, ...y) {
// y 是一個數組
return x * y.length;
}
f(3, "hello", true); // 6
複製代碼
function f(x, y, z) {
return x + y + z;
}
// 將數組的每一項做爲參數傳遞
f(...[1,2,3]); // 6
複製代碼
var [a, ,b] = [1,2,3];
a === 1; // true
b === 3; // true
var { op: a, lhs: { op: b }, rhs: c } = getASTNode()
// var {op: op, lhs: lhs, rhs: rhs} = getASTNode()
var {op, lhs, rhs} = getASTNode()
// 參數解構
function g({name: x}) {
console.log(x);
}
g({name: 5})
var [a] = [];
a === undefined; // true
var [a = 1] = [];
a === 1; // true
// 解構 + 默認參數
function r({x, y, w = 10, h = 10}) {
return x + y + w + h;
}
r({x:1, y:2}) === 23 // true
複製代碼
// 除了支持返回語句,還能夠將表達式做爲返回主體
const foo = () => ({ name: 'es6' });
const bar = (num) => (num++, num ** 2);
foo(); // 返回一個對象 { name: 'es6' }
bar(3); // 執行多個表達式,並返回最後一個表達式的值 16
複製代碼
JS 中 this
的指向問題一直都是面試高頻考點,很多人在實戰中也掉入坑中,總結起來就是一句話:「 this
永遠指向調用它的那個對象」,而箭頭函數則改寫了這一規則,就是編程
箭頭函數共享當前代碼上下文的
this
windows
什麼意思呢?能夠理解爲api
this
,它只會從本身的做用域鏈的上一層繼承 this
,若是上一層仍是箭頭函數,則繼續向上查找,直至全局做用域,在瀏覽器環境下即 window
。所以,在下面的代碼中,傳遞給 setInterval
的函數內的 this
與 sayHello
函數中的 this
一致:數組
const bob = {
name: 'Bob',
sayHello() {
setTimeout(() => {
console.log(`hello, I am ${this.name}`);
}, 1000);
}
};
const hello = bob.sayHello;
bob.sayHello();
// hello, I am Bob
// 做爲對象的方法調用,sayHello的this指向bob
hello();
// hello, I am undefined
// 做爲普通函數調用,至關於window.hello(),this指向全局對象
hello.call({name:'Mike'});
// hello, I am Mike
// call,apply調用,第一個參數爲this指向的對象
複製代碼
language = 'Python';
const obj = {
language: 'TS',
speak() {
language = 'GO';
return function() {
return () => {
console.log(`I speak ${this.language}`);
};
};
}
};
obj.speak()()(); // 作個小測試,會打印什麼呢?
複製代碼
箭頭函數還有如下特色瀏覽器
this
指針,經過 call
或 apply
調用,第一個參數會被忽略Arguments
對象,其引用上一層做用域鏈的 Arguments
對象new
一塊兒用會拋出錯誤。prototype
屬性。如今你應該明白爲什麼 React 中的函數寫法都爲箭頭函數,就是爲了綁定 this
babel
ES6 引入了一種新的原始數據類型 Symbol
,表示獨一無二的值,它的功能相似於一種標識惟一性的 ID數據結構
// 每一個 Symbol 實例都是惟一的。所以,當你比較兩個 Symbol 實例的時候,將總會返回 false
const s1 = Symbol('macOS');
const s2 = Symbol('macOS');
// Symbol.for 機制有點相似於單例模式
const s3 = Symbol.for('windows'); // 註冊一個全局 Symbol
const s4 = Symbol.for('windows'); // 已存在相同名稱的 Symbol,返回全局 Symbol
s1 === s2; // false
s3 === s4; // true
複製代碼
let key = Symbol('key');
function MyClass(privateData) {
// 注意,Symbol值做爲對象屬性名時,不能用點運算符
this[key] = privateData;
}
MyClass.prototype = {
doStuff() {
console.log(this[key]);
}
};
// Symbol的一些特性必需要瀏覽器的原生實現,不可被 transpiled 或 polyfilled
typeof key // symbol
let c = new MyClass('hello');
c.key; // undefined
c[key]; // hello
複製代碼
在實際應用中,咱們常常會須要使用 Object.keys()
或者 for...in
來枚舉對象的屬性名,那在這方面,Symbol
類型的 key
表現的會有什麼不一樣之處呢?來看如下示例代碼:
let obj = {
[Symbol('name')]: '一斤代碼',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分別會輸出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
複製代碼
也正由於這樣一個特性,當使用 JSON.stringify()
將對象轉換成 JSON
字符串的時候,Symbol
屬性也會被排除在輸出內容以外:
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
複製代碼
由上代碼可知,Symbol
類型的 key
是不能經過 Object.keys()
或者 for...in
來枚舉的,因此,利用該特性,咱們能夠把一些不須要對外操做和訪問的屬性使用 Symbol
來定義。
const TYPE_AUDIO = 'AUDIO'
const TYPE_VIDEO = 'VIDEO'
const TYPE_IMAGE = 'IMAGE'
function handleFileResource(resource) {
switch(resource.type) {
case TYPE_AUDIO:
playAudio(resource)
break
case TYPE_VIDEO:
playVideo(resource)
break
case TYPE_IMAGE:
previewImage(resource)
break
default:
throw new Error('Unknown type of resource')
}
}
複製代碼
上面的代碼中那樣,咱們須要爲常量賦一個惟一的值(好比這裏的 'AUDIO'
),'AUDIO'
就是一個魔術字符串,它自己沒意義,只是爲了保證常量惟一的關係。常量一多,就變得十分臃腫且難以理解
如今有了 Symbol
,咱們大可沒必要這麼麻煩了:
// 保證了三個常量的值是惟一的
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()
複製代碼
const obj = {
// 容許設置原型
__proto__: theProtoObj,
// 容許覆蓋屬性
['__proto__']: somethingElse,
// 屬性簡寫,等於 ‘handler: handler’
handler,
// 計算 (動態) 屬性名
['prop_' + (() => 42)()]: 42
};
obj.prop_42 // 42
obj.__proto__ // somethingElse
複製代碼
__proto__
須要原生支持,它在以前的ECMAScript
版本中被移除,但大多數瀏覽器都實現了這一特性,包括Node
環境
Set
是 ES6 中新增的數據結構,它容許建立惟一值的集合。集合中的值能夠是簡單的基本類型(如字符串或數值),但更復雜的對象類型(如對象或數組)也能夠,亦或是一個新的 Set
let animals = new Set();
animals.add('🐷');
animals.add('🐼');
animals.add('🐢');
animals.add('🐿');
console.log(animals.size); // 4
animals.add('🐼');
console.log(animals.size); // 4
console.log(animals.has('🐷')); // true
animals.delete('🐷');
console.log(animals.has('🐷')); // false
animals.forEach(animal => {
console.log(`Hey ${animal}!`);
});
// Hey 🐼!
// Hey 🐢!
// Hey 🐿!
animals.clear();
console.log(animals.size); // 0
複製代碼
咱們還能夠傳入一個數組來初始化集合
let myAnimals = new Set(['🐷', '🐢', '🐷', '🐷']);
myAnimals.add(['🐨', '🐑']);
myAnimals.add({ name: 'Rud', type: '🐢' });
console.log(myAnimals.size); // 4
// Set 內置了遍歷器,能夠調用 forEach, for…of
myAnimals.forEach(animal => {
console.log(animal);
});
// 🐷
// 🐢
// ["🐨", "🐑"]
// Object { name: "Rud", type: "🐢" }
複製代碼
與普通對象(Object
)不一樣,Map
的鍵名(Key
)能夠是任何類型,再也不侷限於字符串(String
),包括但不限於 objects
或 functions
let things = new Map();
const myFunc = () => '🍕';
things.set('🚗', 'Car');
things.set('🏠', 'House');
things.set('✈️', 'Airplane');
things.set(myFunc, '😄 Key is a function!');
things.size; // 4
things.has('🚗'); // true
things.has(myFunc) // true
things.has(() => '🍕'); // false
things.get(myFunc); // '😄 Key is a function!'
things.delete('✈️');
things.has('✈️'); // false
things.clear();
things.size; // 0
// 鏈式設置鍵值對
things.set('🔧', 'Wrench')
.set('🎸', 'Guitar')
.set('🕹', 'Joystick');
const myMap = new Map();
// 甚至鍵名能夠是另外一個 Map
things.set(myMap, 'Oh gosh!');
things.size; // 4
things.get(myMap); // 'Oh gosh!'
複製代碼
能夠經過傳入包含兩個元素的數組來初始化 Map
const funArray = [
['🍾', 'Champagne'],
['🍭', 'Lollipop'],
['🎊', 'Confetti'],
];
let funMap = new Map(funArray);
funMap.get('🍾'); // Champagne
複製代碼
WeakMap
對象是一組鍵/值對的集合,其中的鍵是弱引用的。其鍵必須是對象,而值能夠是任意的。它最重要的特性是 WeakMap
保持了對鍵名所引用的對象的弱引用
咱們能夠經過 Node 來證實一下這個問題:
// 容許手動執行垃圾回收機制
node --expose-gc
global.gc();
// 返回 Nodejs 的內存佔用狀況,單位是 bytes
process.memoryUsage(); // heapUsed: 4640360 ≈ 4.4M
let map = new Map();
let key = new Array(5 * 1024 * 1024); // new Array 當爲 Obj
map.set(key, 1);
global.gc();
process.memoryUsage(); // heapUsed: 46751472 注意這裏大約是 44.6M
// 因此當你設置 key = null 時,只是去掉了 key 對 Obj 的強引用
// 並無去除 arr 對 Obj 的強引用,因此 Obj 仍是不會被回收掉
key = null;
global.gc();
process.memoryUsage(); // heapUsed: 46754648 ≈ 44.6M
// 這句話實際上是無用的,由於 key 已是 null 了
map.delete(key);
global.gc();
process.memoryUsage(); // heapUsed: 46755856 ≈ 44.6M
複製代碼
node --expose-gc
global.gc();
process.memoryUsage(); // heapUsed: 4638992 ≈ 4.4M
const wm = new WeakMap();
let key = new Array(5 * 1024 * 1024);
wm.set(key, 1);
global.gc();
process.memoryUsage(); // heapUsed: 46776176 ≈ 44.6M
// 當咱們設置 key = null 的時候,就只有 wm 對所引用對象的弱引用
// 下次垃圾回收機制執行的時候,該引用對象就會被回收掉。
key = null;
global.gc();
process.memoryUsage(); // heapUsed: 4800792 ≈ 4.6M
複製代碼
傳統使用 jQuery
的時候,咱們會經過 $.data()
方法在 DOM
對象上儲存相關信息(就好比在刪除按鈕元素上儲存帖子的 ID 信息),jQuery
內部會使用一個對象管理 DOM
和對應的數據,當你將 DOM
元素刪除,DOM
對象置爲空的時候,相關聯的數據並不會被刪除,你必須手動執行 $.removeData()
方法才能刪除掉相關聯的數據,WeakMap
就能夠簡化這一操做:
let wm = new WeakMap(), element = document.querySelector(".element");
wm.set(element, "data");
let value = wm.get(elemet);
console.log(value); // data
element.parentNode.removeChild(element);
element = null;
複製代碼
特性與 WeakMap
類似
遍歷器(Iterator
)它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator
接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)。 Iterator
的做用有三個:
for...of
循環,Iterator
接口主要供 for...of
消費。ES6 規定,默認的 Iterator
接口部署在數據結構的 Symbol.iterator
屬性,或者說,一個數據結構只要具備 Symbol.iterator
屬性,就能夠認爲是「可遍歷的」(iterable
)
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur]; // 數組解構
return { done: false, value: cur }
}
}
}
}
for (var n of fibonacci) {
// 當n超過1000時中止
if (n > 1000)
break;
console.log(n);
}
複製代碼
上面代碼中,對象 fibonacci
是可遍歷的(iterable
),由於具備 Symbol.iterator
屬性。執行這個屬性,會返回一個遍歷器對象。該對象的根本特徵就是具備 next
方法。每次調用 next
方法,都會返回一個表明當前成員的信息對象,具備 value
和 done
兩個屬性
原生具有 Iterator
接口的數據結構以下
for (let i in [1, 2, 3]) {
console.log(typeof i); // string 數組下標被轉化字符串
console.log(i); // '1', '2', '3'
}
var triangle = { a: 1, b: 2, c: 3 };
function ColoredTriangle() {
this.color = 'red';
}
ColoredTriangle.prototype = triangle;
var obj = new ColoredTriangle();
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) { // 若是去了 hasOwnProperty() 這個約束條件會怎麼樣?
console.log(`obj.${prop} = ${obj[prop]}`); // obj.color = red
}
}
複製代碼
咱們先來看看新增的 Number.EPSILON
,很多人都是懵逼的狀態,WTF?
先來看看的 JS 世界中的一道送命題
0.1 + 0.2 // 結果0.30000000000000004 而不是0.3
複製代碼
事出必有因,這是由於 JS 的數值採用了 IEEE 754
標準,並且 JS 是弱類型語言,因此數字都是以64位雙精度浮點數據類型儲存。也就是說,JS 語言底層根本沒有整數,全部數字都是小數!當咱們覺得在用整數進行計算時,都會被轉換爲小數
而浮點數都是以多位二進制的方式進行存儲的
十進制的0.1用二進制表示爲:0.0 0011 0011 0011 0011…,循環部分是0011
十進制0.2用二進制表示爲:0.0011 0011 0011 0011…,循環部分是0011
因爲存儲空間有限,最後計算機會捨棄後面的數值,因此咱們最後就只能獲得一個近似值
JS中採用的 IEEE 754
的雙精度標準也是同樣的道理在存儲空間有限的狀況下,當出現這種沒法整除的小數的時候就會取一個近似值,在 JS 中若是這個近似值足夠近似,那麼 JS 就會認爲他就是那個值。
console.log(0.1000000000000001)
// 0.1000000000000001 (中間14個0,不會被近似處理,輸出自己)
console.log(0.10000000000000001)
// 0.1 (中間15個0,js會認爲兩個值足夠近似,因此輸出0.1)
複製代碼
那麼這個近似的界限如何判斷呢?
ES6的 Number.EPSILON
就是一個界限,它表示 1 與大於 1 的最小浮點數之間的差。
對於 64 位浮點數來講,大於 1 的最小浮點數至關於二進制的1.00..001,小數點後面有連續 51 個零。這個值減去 1 以後,就等於 2 的 -52 次方
Number.EPSILON === Math.pow(2, -52)
// true
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"
複製代碼
Number.EPSILON
其實是 JavaScript 可以表示的最小精度。偏差若是小於這個值,就能夠認爲已經沒有意義了,即不存在偏差了。
0.1 + 0.2 - 0.3
// 5.551115123125783e-17
5.551115123125783e-17.toFixed(20)
// '0.00000000000000005551'
複製代碼
0.00000000000000005551 < 0.00000000000000022204 // true
複製代碼
顯然,0.30000000000000004
不存在偏差,不會被近似處理
咱們能夠經過如下手段來達到咱們想要的效果
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true
複製代碼
其餘一些新增的 API
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
Math.sign(-5) // 判斷一個數究竟是正數、負數、仍是零 -1
Math.hypot(3, 4) // 返回全部參數的平方和的平方根 5
Math.imul(-2, -2) // 返回兩個數以 32 位帶符號整數形式相乘的結果 4
"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
Array.from(document.querySelectorAll("*")) // 返回一個真正的數組
Array.of(1, 2, 3) // [1,2,3]
[0, 0, 0].fill(7, 1) // [0,7,7]
[1,2,3].findIndex(x => x == 2) // 1
["a", "b", "c"].entries() // [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // 0, 1, 2
["a", "b", "c"].values() // "a", "b", "c"
Object.assign(Point, { origin: new Point(0,0) }) // 合併對象
複製代碼
0b111 === 7 // true 二進制
0o111 === 73 // true 八進制
0x111 === 273 // true 十六進制
複製代碼
假設如今要實現一個階乘函數,即 5!= 120
,咱們很容易想到遞歸實現
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
複製代碼
但遞歸很是耗費內存,由於須要同時保存成千上百個調用記錄,很容易發生"棧溢出"錯誤(stack overflow
)。但對於尾遞歸來講,因爲只存在一個調用記錄,因此永遠不會發生"棧溢出"錯誤。
何爲調用記錄,在示例代碼中,因爲最後一步返回了一個表達式,內存會保留
n
這個變量的信息和factorial(n - 1)
調用下一次函數的位置,造成一層層的調用棧
尾遞歸的實現,每每須要改寫遞歸函數,確保最後一步只調用自身,返回函數自己。作到這一點的方法,就是把全部用到的內部變量改寫成函數的參數。尾遞歸優化以下
function factorial(n, acc = 1) {
"use strict";
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
factorial(100000)
複製代碼
因而可知,"尾調用優化"對遞歸操做意義重大,因此一些函數式編程語言將其寫入了語言規格。ES6 也是如此,第一次明確規定,全部 ECMAScript
的實現,都必須部署"尾調用優化"。這就是說,在 ES6 中,只要使用尾遞歸,就不會發生棧溢出,相對節省內存。
ES6的尾調用優化只在嚴格模式下開啓,正常模式是無效的。
Reflect
對象與 Proxy
對象同樣,也是 ES6 爲了操做對象而提供的新 API。Reflect
對象的設計目的有這樣幾個。
Object.defineProperty
),放到 Reflect
對象上Object
方法的返回結果,讓其變得更合理。好比,Object.defineProperty(obj, name, desc)
在沒法定義屬性時,會拋出一個錯誤,而 Reflect.defineProperty(obj, name, desc)
則會返回 false
。var O = {a: 1};
Reflect.defineProperty(O, 'b', {value: 2});
O[Symbol('c')] = 3;
Reflect.ownKeys(O); // ['a', 'b', Symbol(c)]
Reflect.getOwnPropertyDescriptor(O, 'b');
// { value: 2, writable: false, enumerable: false, configurable: false }
function C(a, b){
this.c = a + b;
}
var instance = Reflect.construct(C, [20, 22]);
instance.c; // 42
複製代碼
獲取屬性名的方法有不少,以上面的代碼爲例子,它們的區別以下
方法 | 結果 | 解釋 |
---|---|---|
Object.getOwnPropertyNames(O) |
[ 'a', 'b' ] |
自身除 Symbol 外的屬性 |
Object.getOwnPropertySymbols(O) |
[ Symbol(c) ] |
自身 Symbol 屬性 |
Object.keys(O) |
['a'] |
自身除 Symbol 外可枚舉屬性 |
Reflect.ownKeys(O) |
[ 'a', 'b', Symbol(c) ] |
自身全部屬性 |
for...in |
a |
自身和原型鏈,除 Symbol 外的可枚舉屬性 |
Proxy
能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。Proxy
這個詞的原意是代理,用在這裏表示由它來「代理」某些操做,能夠譯爲「代理器」。
// 代理一個對象
var target = {};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}!`;
}
};
var p = new Proxy(target, handler);
p.world; // "Hello, world!"
複製代碼
// 代理一個函數
var target = function () { return "I am the target"; };
var handler = {
apply: function (receiver, ...args) {
return "I am the proxy";
}
};
var p = new Proxy(target, handler);
p(); // "I am the proxy"
複製代碼
// 代理會將全部應用到它的操做轉發到這個對象上
let target = {};
let p = new Proxy(target, {});
p.a = 37;
target.a; // 37 操做轉發到目標
複製代碼
// 如何實現 a == 1 && a == 2 && a == 3,利用Proxy的get劫持
const a = new Proxy(
{},
{
val: 1,
get() {
return () => this.val++;
}
}
);
a == 1 && a == 2 && a == 3; // true
複製代碼
因爲 ES5 的限制,Proxy 不能被 transpiled or polyfilled,本身親自入的坑,因爲在項目中使用了 Mobx5.x,其內部是用 Proxy 寫的,結果 IE11 不支持 ES6,只得回退版本 Mobx 到 4.x
Generator
函數是 ES6 提供的一種異步編程解決方案。 Generator
函數有多種理解角度。語法上,首先能夠把它理解成,Generator
函數是一個狀態機,封裝了多個內部狀態。
形式上,Generator
函數是一個普通函數,可是有兩個特徵。一是,function
關鍵字與函數名之間有一個星號;二是,函數體內部使用 yield
表達式,定義不一樣的內部狀態
function* helloWorldGenerator() {
yield 'hello'; // yield使Generator函數暫停了執行,並將結果返回給調用者
yield 'world'; // 當下一次調用時,從它中斷的地方恢復執行
return 'ending';
}
var hw = helloWorldGenerator();
a = hw.next(); // { value: 'hello', done: false }
b = hw.next(); // { value: 'world', done: false }
c = hw.next(); // { value: 'ending', done: true }
複製代碼
能夠利用這種暫停執行的特性,來實現惰性求值
function* sayFullName() {
const firstName = yield;
const secondName = yield;
console.log(firstName + ' ' + secondName);
}
let fullName = sayFullName();
fullName.next();
// 第一次調用,代碼暫停在 const firstName = yield,由於沒有經過 yield 發送任何值,所以 next 將返回 undefined
fullName.next('Handsome');
// 第二次調用,傳入了值 Handsome,yield 被 Handsome 替代,所以 firstName 的值變爲 Handsome,代碼執行恢復
// 直到再次遇到 const secondName = yield 暫停執行
fullName.next('Jack');
// 第三次調用,傳入了值 Jack,yield 被 Jack 替代,所以 secondName 的值變爲 Jack,代碼執行恢復
// 打印 Handsome Jack
複製代碼
let generator;
let getDataOne = () => {
setTimeout(() => {
generator.next('dummy data one');
}, 1000);
};
let getDataTwo = () => {
setTimeout(() => {
generator.next('dummy data one');
}, 1000);
};
function* main() {
let dataOne = yield getDataOne();
let dataTwo = yield getDataTwo();
console.log(dataOne, dataTwo);
}
generator = main();
generator.next();
// 執行 getDataOne(),而後 yield 暫停
// 直至一秒後 generator.next('dummy data one') 恢復代碼執行,並賦值 dataOne
console.log('i am previous print');
// i am previous print
// dummy data one dummy data one
複製代碼
Promises
是一個異步編程的解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。
所謂 Promise
,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise
是一個對象,從它能夠獲取異步操做的消息。Promise
提供統一的 API
,各類異步操做均可以用一樣的方法進行處理。
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
複製代碼
這裏強調幾點
return
的能力,不少人寫 Promise
,照樣有大量嵌套,掉進 Promise
地獄,要記得及時 return
,避免嵌套Promise.all(fetch1,fetch2)
Promise.race(fetch1,fetch2)
ES6 是 ECMAScript
一個很是重要的版本,咱們必須深刻理解,不只能提升咱們書寫代碼的能力,還能加強業務能力
附上一張我以前精心整理的思惟導圖
本文參考資料