最近做了一些面试题,
const myPromise = Promise.resolve('Woah some coll data');
(async () => {
try{
console.log(await myPromise);
} catch {
throw new Error(`Oops did't work`);
} finally {
console.log('Oh finally!');
}
})();
输出:
Woah Some coll data Oh finally
function* startGame() {
const answer = yield 'Do you love JavaScript?';
if (answer !== 'yes'){
return "Oh wow... Guess we're gone here";
}
return 'JavaScript loves you back';
}
const game = startGame();
console.log(); // 如何输出 Do you love JavaScript?
console.log(); // 如何输出 JavaScript loves you back;
A game.next('yes').value and game.next().value
B game.next.value('yes') and game.next.value()
C game.next().value and game.next('yes').value
D game.next.value() and game.next.value('yes')
看到async 和 await 等一些知识点,突然感觉好像不是对这两个关键字特别熟悉,所以就专门写一个文档记录下自己的学习。
1. async function
用来定义一个返回AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。
返回的Promise 对象会运行执行(resolve)异步函数的返回结果,或者运行拒绝(reject)-如果异步函数抛出异常的话。
2. await 操作符
await 操作符用于等待一个Promise对象。他只能在异步函数async Function 中使用。
语法: [return_value] = await expression
;
返回值:
返回 Promise 对象的处理结果。如果表达式不是Promise,则返回该值本身。
注意: await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成,然后继续执行下面的程序。
若Promise 正常处理(fulfilled),其 回调的resolve函数参数作为await表达式的值,继续执行 async function .
若Promise 处理异常(rejected),await表达式会把Promise 的异常原因抛出。
function fn2(x){
return new Promise(resolve => {
setTimeout(() => {
resolve(x)''
}, 2000)
});
}
async function f1(){
let x = await 2; // 2
let y = await fn2(10); // y = 10
}
3. yield
键字用来暂停和恢复一个生成器函数((function* 或遗留的生成器函数)。
[rv] = yield [expression]
expression 定义通过 迭代器协议从生成器函数返回的值。如果省略,则返回undefined rv 返回传递给生成器的next() 方法的可选值,以恢复其执行。
描述
yield 关键字使生成器函数执行暂停,yield 关键字后面的表达式的值返回给生成器的调用者。
yield 关键字时间返回一个 IteratorResult 对象, 它有两个属性 value 和 done, value 属性是对 yield表达式求值的结果,而done 是false, 表示生成器函数尚未完全完成。
一旦遇到 yield 表达式,生成器的代码将会被暂停执行,直到生成器的 next() 方法被调用。每次调用生成器 next() 方法时,生成器都会恢复执行,直到达到以下某个值:
- yield,导致生成器再次暂停并返回生成器的新值。下一次调用next()时,在yield之后紧接着的语句继续执行。
- throw用于从生成器中抛出异常。这让生成器完全停止执行,并在调用者中继续执行,正如通常情况下抛出异常一样。
- 到达生成器函数的结尾;在这种情况下,生成器的执行结束,并且IteratorResult给调用者返回undefined并且done为true。
- 到达return 语句。在这种情况下,生成器的执行结束,并将IteratorResult返回给调用者,其值是由return语句指定的,并且done 为true。
function* countAppleSales () {
var saleList = [3, 7, 5];
for (var i = 0; i < saleList.length; i++) {
yield saleList[i];
}
}
let appleStore = countAppleSales(); // Generator { }

4. function*
functino* 这种生命方式(function关键字后跟一个星号)会定义一个生成器函数,它返回一个 Generator 对象。
function* generator(i) {
yield i;
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value);
// expected output: 10
console.log(gen.next().value);
// expected output: 20
描述
生成器函数在执行时能暂停,后面又能从暂停处继续执行。
调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的迭代器对象。当这个迭代器的 next() 方法被首次调用时,其内的语句会执行到第一个 出现 yield 的位置为止,yield 后紧跟迭代器要返回的值。
或者如果用的是 yield*
,则表示将执行权移交给另外一个生成器函数(当前生成器暂停执行)。
next() 方法返回一个对象,这个对象包含两个属性: value 和 done , value 属性表示本次 yield 表达式的返回值,done 表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回。
调用 next() 方法时,如果传入了参数,那么这个参数会传给上一条执行的yield语句左边的变量
function *gen(){
yield 10;
x=yield 'foo';
yield x;
}
var gen_obj=gen();
console.log(gen_obj.next());// 执行 yield 10,返回 10
console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo'
console.log(gen_obj.next(100));// 将 100 赋给上一条 yield 'foo' 的左值,即执行 x=100,返回 100
console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true
当在生成器函数中显式 return 时,会导致生成器立即变为完成状态,即调用 next() 方法返回的对象的 done 为 true。如果 return 后面跟了一个值,那么这个值会作为当前调用 next() 方法返回的 value 值。
5. yield*
yield*表达式 用于委托给另外一个 generator 或可迭代对象
yield* [[expression]]
** expression ** 返回一个可迭代对象的表达式(例如数组)
描述
yield* 表达式 迭代操作数,并返回它返回的每个值。
yield* 表达式本身的值是当迭代器关闭时返回的值(当done为true,即为关闭)
委托给其他生成器
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
let iterator = g2();

委托给其他可迭代对象
除了生成器对象这一种可迭代对象,yield* 还可以 yield 其它任意的可迭代对象,比如说数组、字符串、arguments 对象等等。
function* g3() {
yield* [1, 2];
yield* '34';
yield* arguments;
}
let iterator = g3(5,6);

yield* 表达式的值
yield* 是一个表达式,不是语句,所以它会有自己的值。
function* g4 () {
yield* [1,2,3];
return 'foo';
}
let result;
function* g5 () {
result = yield* g4();
}
let iterator = g5();

题一
yield* function* 代码分析:
function* generatorOne () {
yield ['a', 'b', 'c'];
}
function* generatorTwo (){
yield* ['a', 'b', 'c'];
}
let one = generatorOne();
let two = generatorTwo();
console.log(one.next().value);
console.log(two.next().value);
// 输出
["a", "b", "c"]
a
代码解析:
通过yield 关键字,我们在 Generator 函数里执行yield 表达式,通过 yield* 关键字,我们可也在一个 Generator 函数中执行 (yield表达式),另一个 Generator 函数,或可遍历的对象(如数组)。
在函数 generatorOne
中,我们通过 yield 关键字,yield 了一个完整的数组 ['a', 'b', 'c'], 函数one 通过next方法返回的对象的value 值应该为['a', 'b', 'c']。
在函数generatorTwo
中,我们使用了 yield* 关键字,就相当于函数 two 第一个 yield 的值,等价于在迭代器中第一个 yield 的值。数组也是一个迭代器,会对应的迭代数组中的内容,依次迭代'a', 'b','c'。
题二
function* 调用 next() 方法时,如果传入了参数,那么这个参数会传给上一条执行的yield语句左边的变量,
function* startGame() {
const answer = yield 'Do you love JavaScript?';
if (answer !== 'yes'){
return "Oh wow... Guess we're gone here";
}
return 'JavaScript loves you back';
}
const game = startGame();
console.log(); // 如何输出 Do you love JavaScript?
console.log(); // 如何输出 JavaScript loves you back;
A game.next('yes').value and game.next().value
B game.next.value('yes') and game.next.value()
C game.next().value and game.next('yes').value
D game.next.value() and game.next.value('yes')
function* 函数遇到yield 关键字会“暂停”其执行。首先我们需要输出“Do you love JavaScript?” , 这可以通过调用 game.next().value来完成,其次,answer 需要和 ‘yes’ 对比,上面有个知识点 ,当function* 调用 next() 方法时,如果传入了参数,那么这个参数会传给上一条执行的yield语句左边的变量, 因此game.next('yes').value 就可以了