异步“队列”中的“for wait”循环如何在“入队”之前调用“出队”?它在放入队列之前返回 new Promise()

问题描述 投票:0回答:1

我是 Javascript 新手,一直在阅读 David's Flanagan Guide 以了解总体概况。

这段代码让我很困惑。我无法意识到循环中的 Promise 在“入队”之前是如何“出队”的?

首先我们将所有 Promise 放入 AsyncQueue() 中:

function eventStream(elt, type) {
  const q = new AsyncQueue(); // Create a queue
  elt.addEventListener(type, (e) => q.enqueue(e)); // Enqueue events
  return q;
}

然后我们迭代它的值:

async function handleKeys() 
// Get a stream of keypress events and loop once for each one
  for await (const event of eventStream(document, "keypress")) {
    console.log(event.key);
  }
}

所以我想知道“for wait”循环中的“事件”怎么可能在队列中没有事件?我们之前不是已经说过了吗

“Forawait”循环在“Promise”进入“队列”之前将其“出队”。但如何呢? “for wait”运算符不会等到下一个 Promised 得到解决吗?

也许队列 - eventStream(document, "keypress") - 动态变化? 抱歉,我感觉很困惑。

整个代码片段:

/**
 * An asynchronously iterable queue class. Add values with enqueue()
 * and remove them with dequeue(). dequeue() returns a Promise, which
 * means that values can be dequeued before they are enqueued. The
 * class implements [Symbol.asyncIterator] and next() so that it can
 * be used with the for/await loop (which will not terminate until
 * the close() method is called.)
 */
class AsyncQueue {
  constructor() {
    // Values that have been queued but not dequeued yet are stored here
    this.values = [];
    // When Promises are dequeued before their corresponding values are
    // queued, the resolve methods for those Promises are stored here.
    this.resolvers = [];
    // Once closed, no more values can be enqueued, and no more unfulfilled
    // Promises returned.
    this.closed = false;
  }

  enqueue(value) {
    if (this.closed) {
      throw new Error("AsyncQueue closed");
    }
    if (this.resolvers.length > 0) {
      // If this value has already been promised, resolve that Promise
      const resolve = this.resolvers.shift();
      resolve(value);
    } else {
      // Otherwise, queue it up
      this.values.push(value);
    }
  }

  dequeue() {
    if (this.values.length > 0) {
      // If there is a queued value, return a resolved Promise for it
      const value = this.values.shift();
      return Promise.resolve(value);
    } else if (this.closed) {
      // If no queued values and we're closed, return a resolved
      // Promise for the "end-of-stream" marker
      return Promise.resolve(AsyncQueue.EOS);
    } else {
      // Otherwise, return an unresolved Promise,
      // queuing the resolver function for later use
      return new Promise((resolve) => {
        this.resolvers.push(resolve);
      });
    }
  }

  close() {
    // Once the queue is closed, no more values will be enqueued.
    // So resolve any pending Promises with the end-of-stream marker
    while (this.resolvers.length > 0) {
      this.resolvers.shift()(AsyncQueue.EOS);
    }
    this.closed = true;
  }

  // Define the method that makes this class asynchronously iterable
  [Symbol.asyncIterator]() {
    return this;
  }

  // Define the method that makes this an asynchronous iterator. The
  // dequeue() Promise resolves to a value or the EOS sentinel if we're
  // closed. Here, we need to return a Promise that resolves to an
  // iterator result object.
  next() {
    return this.dequeue().then((value) =>
      value === AsyncQueue.EOS
        ? { value: undefined, done: true }
        : { value: value, done: false }
    );
  }
}

// A sentinel value returned by dequeue() to mark "end of stream" when closed
AsyncQueue.EOS = Symbol("end-of-stream");

// Push events of the specified type on the specified document element
// onto an AsyncQueue object, and return the queue for use as an event stream
function eventStream(elt, type) {
  const q = new AsyncQueue(); // Create a queue
  elt.addEventListener(type, (e) => q.enqueue(e)); // Enqueue events
  return q;
}

async function handleKeys() {
  // Get a stream of keypress events and loop once for each one
  for await (const event of eventStream(document, "keypress")) {
    console.log(event.key);
  }
}

let a = handleKeys();

谢谢有人能解释这个基本问题。 我查遍了整个互联网,但没有找到解释。

javascript async-await async.js
1个回答
0
投票

Promise 的整个概念(就其名称而言)是,当创建/提供 Promise 时,我们还没有发生解决 Promise 的事件。所以在承诺队列中没有任何事件。这只是对所有事件的抽象,例如将要发生的

keypress
事件。使用
for await
开始迭代未来事件。希望这可以帮助理解。队列并不意味着其中的所有事件都已发生。

© www.soinside.com 2019 - 2024. All rights reserved.