语法上,Generator 函数是一个状态机,封装了多个内部状态。执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,仍是一个遍历器对象生成函数。返回的遍历器对象,能够依次遍历 Generator 函数内部的每个状态。数组
形式上,Generator 函数是一个普通函数,可是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不一样的内部状态。promise
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
复制代码
上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。bash
Generator 函数的调用方法与普通函数同样,也是在函数名后面加上一对圆括号。不一样的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)。异步
下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator函数是分段执行的,yield表达式是暂停执行的标记,而next方法能够恢复执行。async
因为 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,因此其实提供了一种能够暂停执行的函数。yield表达式就是暂停标志。函数
遍历器对象的next方法的运行逻辑以下。ui
Generator 函数返回的遍历器对象,都有一个throw方法,能够在函数体外抛出错误,而后在 Generator 函数体内捕获。spa
var g = function* () {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
// 内部捕获 a
// 外部捕获 b
复制代码
上面代码中,遍历器对象i连续抛出两个错误。第一个错误被Generator函数体内的catch语句捕获。i第二次抛出错误,因为Generator函数内部的catch语句已经执行过了,不会再捕捉到这个错误了,因此这个错误就被抛出了 Generator 函数体,被函数体外的catch语句捕获。prototype
Generator 函数返回的遍历器对象,还有一个return方法,能够返回给定的值,而且终结遍历 Generator 函数。指针
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
复制代码
若是return方法调用时,不提供参数,则返回值的value属性为undefined。
若是 Generator 函数内部有try...finally代码块,且正在执行try代码块,那么return方法会推迟到finally代码块执行完再执行。
Promise 异步操做有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。除了异步操做的结果,任何其余操做都没法改变这个状态。
Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。
then 方法接收两个函数做为参数,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。两个函数只会有一个被调用。
const promise = new Promise(function(resolve, reject) {
if (/* 异步操做成功 */){
resolve(value)
} else {
reject(error)
}
})
promise.then(function(value) {
// success
}, function(error) {
// failure
})
复制代码
Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。 通常来讲,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),老是使用catch方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
复制代码
finally方法用于指定无论 Promise 对象最后状态如何,都会执行的操做。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···})
复制代码
上面代码中,无论promise最后的状态,在执行完then或catch指定的回调函数之后,都会执行finally方法指定的回调函数。
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3])
复制代码
上面代码中,Promise.all方法接受一个数组做为参数,p一、p二、p3都是 Promise,p的状态由p一、p二、p3决定,分红两种状况。
Promise.race方法一样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3])
复制代码
上面代码中,只要p一、p二、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。
有时须要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个做用。
参数是一个 Promise 实例
若是参数是 Promise 实例,那么Promise.resolve将不作任何修改、原封不动地返回这个实例。
参数是一个thenable对象
Promise.resolve方法会将这个对象转为 Promise 对象,而后就当即执行thenable对象的then方法。
参数不是具备then方法的对象,或根本就不是对象
若是参数是一个原始值,或者是一个不具备then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
不带有任何参数
Promise.resolve()方法容许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
async函数返回一个 Promise 对象,可使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操做完成,再接着执行函数体内后面的语句。
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name)
const stockPrice = await getStockPrice(symbol)
return stockPrice
}
getStockPriceByName('goog').then(function (result) {
console.log(result)
})
复制代码
async函数返回一个 Promise 对象。 async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function f() {
return 'hello world'
}
f().then(v => console.log(v))
// "hello world"
复制代码
上面代码中,函数f内部return命令返回的值,会被then方法回调函数接收到。
async函数内部抛出错误,会致使返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
async function f() {
throw new Error('出错了')
}
f().then(
v => console.log(v),
e => console.log(e)
)
// Error: 出错了
复制代码
async function f() {
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
复制代码
// good
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// bad
async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err)
})
}
复制代码
// good
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// bad
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
复制代码