【问题标题】:In JavaScript, is `return someValue` in a generator function an anti-pattern?在 JavaScript 中,生成器函数中的“return someValue”是反模式吗?
【发布时间】:2020-04-23 00:45:48
【问题描述】:

下面.next()可以显示最后一个值:{ value: 3, done: true }

function* genFn() {
  yield 1;
  yield 2;
  return 3;
}

const iter = genFn();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

但如果用作可迭代对象则不是:

function* genFn() {
  yield 1;
  yield 2;
  return 3;
}

const iter = genFn();
console.log([...iter]);

似乎无论使用return value 还是不使用return,意思是return undefined,如果它是可迭代协议并且因此也是迭代器协议,则不使用该值。

【问题讨论】:

    标签: javascript ecmascript-6 generator anti-patterns


    【解决方案1】:

    我认为换句话说,return someValue 在生成器函数反模式中吗?

    不,但你应该只在有意义的时候使用它。除了手动调用.next()yield* 也会产生它。

    function* a() {
        yield 1;
        yield 2;
        return 3;
    }
    
    function* b() {
        console.log(yield* a());
    }
    
    console.log([...b()]);

    一个非常实用的例子是预异步函数,其中yield 可以用作await,您仍然希望返回一个值。在编写不基于 promises/thenables 的类似模式时,同样的概念仍然适用。

    不受JavaScript调用栈限制的递归,例如:

    function* sillyAdd(a, b) {
        return b === 0
            ? a
            : yield sillyAdd(a + 1, b - 1);
    }
    
    const restack = f => (...args) => {
        const stack = [f(...args)];
        let ret = undefined;
    
        while (stack.length !== 0) {
            let {value, done} = stack[stack.length - 1].next(ret);
    
            if (done) {
                stack.pop();
                ret = value;
            } else {
                stack.push(value);
            }
        }
    
        return ret;
    };
    
    console.log(restack(sillyAdd)(2, 100000));
    console.log('(it’s synchronous)');

    通过在暂停函数中保持状态进行在线解析:

    function* isBalanced() {
        let open = 0;
    
        for (let c; c = yield;) {
            if (c === '(') {
                open++;
            } else if (c === ')') {
                open--;
    
                if (open < 0) {
                    return false;
                }
            }
        }
    
        return open === 0;
    }
    
    class Parser {
        constructor(generator) {
            this.generator = generator();
            const initial = this.generator.next();
            this.done = initial.done;
            this.result = initial.value;
        }
    
        write(text) {
            if (this.done) {
                return;
            }
    
            for (const c of text) {
                const {value, done} = this.generator.next(c);
    
                if (done) {
                    this.done = true;
                    this.result = value;
                    break;
                }
            }
        }
    
        finish() {
            if (this.done) {
                return this.result;
            }
    
            const {value, done} = this.generator.next();
    
            if (!done) {
                throw new Error('Unexpected end of input');
            }
    
            return value;
        }
    }
    
    const p = new Parser(isBalanced);
    
    // the product of these could be too large to fit in memory
    const chunk = '()'.repeat(1000);
    
    for (let i = 0; i < 100; i++) {
        p.write(chunk);
    }
    
    console.log(p.finish());

    【讨论】:

    • 有趣的yield* a() 会产生它,但它是用来做什么的呢?
    • @nopole:任何东西,比如正常的返回值。 yield 可以暂停功能。有时你仍然想从那个函数的末尾得到一些东西。也许这看起来很奇怪,因为它没有出现很多,这是真的。您可能也不经常使用(yield) 表单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    相关资源
    最近更新 更多