diff --git a/spec.bs b/spec.bs
index f5bb7d5..bf4fbe3 100644
--- a/spec.bs
+++ b/spec.bs
@@ -30,6 +30,7 @@ urlPrefix: https://tc39.es/ecma262/#; spec: ECMASCRIPT
text: normal completion; url: sec-completion-record-specification-type
text: NormalCompletion; url: sec-normalcompletion
text: throw completion; url: sec-completion-record-specification-type
+ text: Iterator Record; url: sec-iterator-records
url: sec-returnifabrupt-shorthands
text: ?
text: !
@@ -490,9 +491,106 @@ An internal observer is a [=struct=] with the following [=struct/item
1. From Observable: If |value|'s [=specific type=]
is an {{Observable}}, then return |value|.
- 1. Issue: Spec the From async iterable conversion steps which take place before
- the iterable conversion steps. See issue #191.
+ 1. From async iterable: Let
+ |asyncIteratorMethod| be [=?=] [$GetMethod$](|value|, {{%Symbol.asyncIterator%}}).
+
+ Note: We use [$GetMethod$] instead of [$GetIterator$] because we're only probing for async
+ iterator protocol support, and we don't want to throw if it's not implemented.
+ [$GetIterator$] throws errors in BOTH of the following cases: (a) no iterator protocol is
+ implemented, (b) an iterator protocol is implemented, but isn't callable or its getter
+ throws. [$GetMethod$] lets us ONLY throw in the latter case.
+
+ 1. If |asyncIteratorMethod|'s is undefined or null, then jump to the step labeled From iterable.
+
+ 1. Let |nextAlgorithm| be the following steps, given a {{Subscriber}} |subscriber| and an
+ [=Iterator Record=] |iteratorRecord|:
+
+ 1. If |subscriber|'s [=Subscriber/subscription controller=]'s [=AbortController/signal=] is
+ [=AbortSignal/aborted=], then return.
+
+ 1. Let |nextPromise| be a {{Promise}}-or-undefined, initially undefined.
+
+ 1. Let |nextCompletion| be [$IteratorNext$](|iteratorRecord|).
+
+ Note: We use [$IteratorNext$] here instead of [$IteratorStepValue$], because
+ [$IteratorStepValue$] expects the iterator's `next()` method to return an object that
+ can immediately be inspected for a value, whereas in the async iterator case, `next()`
+ is expected to return a Promise/thenable (which we wrap in a Promise and react to to get
+ that value).
+
+ 1. If |nextCompletion| is a [=throw completion=], then:
+
+ 1. [=Assert=]: |iteratorRecord|'s \[[Done]] is true.
+
+ 1. Set |nextPromise| to [=a promise rejected with=] |nextRecord|'s \[[Value]].
+
+ 1. Otherwise, if |nextRecord| is [=normal completion=], then set |nextPromise| to [=a
+ promise resolved with=] |nextRecord|'s \[[Value]].
+
+ Note: This is done in case |nextRecord|'s \[[Value]] is not *itself* already a
+ {{Promise}}.
+
+ 1. [=React=] to |nextPromise|:
+
+ * If |nextPromise| was fulfilled with value |iteratorResult|, then:
+
+ 1. If [$Type$](|iteratorResult|) is not Object, then run |subscriber|'s
+ {{Subscriber/error()}} method with a {{TypeError}} and abort these steps.
+
+ 1. Let |done| be [$IteratorComplete$](|iteratorResult|).
+
+ 1. If |done| is a [=throw completion=], then run |subscriber|'s
+ {{Subscriber/error()}} method with |done|'s \[[Value]] and abort these steps.
+
+ 1. If |done|'s \[[Value]] is true, then run |subscriber|'s {{Subscriber/complete()}}
+ and abort these steps.
+
+ 1. Run |nextAlgorithm|.
+
+ * If |nextPromise| was rejected with reason |r|, then run |subscriber|'s
+ {{Subscriber/error()}} method given |r|.
+
+ 1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an algorithm that
+ takes a {{Subscriber}} |subscriber| and does the following:
+
+ 1. If |subscriber|'s [=Subscriber/subscription controller=]'s [=AbortController/signal=] is
+ [=AbortSignal/aborted=], then return.
+
+ 1. Let |iteratorRecordCompletion| be [$GetIterator$](|value|, async).
+
+ Note: This both re-invokes any {{%Symbol.asyncIterator%}} method getters on |value|—note
+ that whether this is desirable is an extreme corner case, but it matches test
+ expectations; see issue#127 for
+ discussion—and invokes the protocol itself to obtain an [=Iterator Record=].
+
+ 1. If |iteratorRecordCompletion| is a [=throw completion=], then run |subscriber|'s
+ {{Subscriber/error()}} method with |iteratorRecordCompletion|'s \[[Value]] and abort these
+ steps.
+
+ Note: This means we invoke the {{Subscriber/error()}} method synchronously with respect to
+ subscription, which is the only time this can happen for async iterables that are
+ converted to {{Observable}}s. In all other cases, errors are propagated to the observer
+ asynchronously, with microtask timing, by virtue of being wrapped in a rejected
+ {{Promise}} that |nextAlgorithm| [=reacts=] to. This synchronous-error-propagation
+ behavior is consistent with language constructs, i.e., **for-await of** loops that invoke
+ {{%Symbol.asyncIterator%}} and synchronously re-throw exceptions to catch blocks outside
+ the loop, before any [$Await|Awaiting$] takes place.
+
+ 1. Let |iteratorRecord| be [=!=] |iteratorRecordCompletion|.
+
+ 1. [=Assert=]: |iteratorRecord| is an [=Iterator Record=].
+
+ 1. If |subscriber|'s [=Subscriber/subscription controller=]'s [=AbortController/signal=] is
+ [=AbortSignal/aborted=], then return.
+
+ 1. [=AbortSignal/add|Add the following abort algorithm=] to |subscriber|'s
+ [=Subscriber/subscription controller=]'s [=AbortController/signal=]:
+
+ 1. Run [$AsyncIteratorClose$](|iteratorRecord|, [=NormalCompletion=](|subscriber|'s
+ [=Subscriber/subscription controller=]'s [=AbortSignal/abort reason=])).
+
+ 1. Run |nextAlgorithm| given |subscriber| and |iteratorRecord|.
1. From iterable: Let |iteratorMethod| be [=?=]
[$GetMethod$](|value|, {{%Symbol.iterator%}}).