diff --git a/asyncstdlib/itertools.py b/asyncstdlib/itertools.py
index b299840..dfdfd7f 100644
--- a/asyncstdlib/itertools.py
+++ b/asyncstdlib/itertools.py
@@ -199,22 +199,26 @@ async def islice(iterable: AnyIterable[T], *args: Optional[int]) -> AsyncIterato
     s = slice(*args)
     start, stop, step = s.start or 0, s.stop, s.step or 1
     async with ScopedIter(iterable) as async_iter:
-        # always consume the first ``start - 1`` items, even if the slice is empty
+        # always consume the first ``start`` items, even if the slice is empty
         if start > 0:
             async for _count, element in aenumerate(_borrow(async_iter), start=1):
                 if _count == start:
                     break
         if stop is None:
             async for idx, element in aenumerate(async_iter, start=0):
-                if idx % step == 0:
+                if not idx % step:
                     yield element
+        elif stop <= start:
+            return
         else:
-            stop -= start
+            # We would actually check ``idx >= stop -1`` later on.
+            # Since we do that for every ``idx``, we subtract ``1`` once here.
+            stop -= start + 1
             async for idx, element in aenumerate(async_iter, start=0):
-                if idx >= stop:
-                    return
                 if not idx % step:
                     yield element
+                if idx >= stop:
+                    return
 
 
 async def starmap(

diff --git a/unittests/test_itertools.py b/unittests/test_itertools.py
index 21b1e8f..7585524 100644
--- a/unittests/test_itertools.py
+++ b/unittests/test_itertools.py
@@ -150,6 +150,28 @@ async def test_islice(iterable, slicing):
     assert await a.list(a.islice(asyncify(iterable), *slicing)) == expected
 
 
+async def ayield_exactly(count: int):
+    for item in range(count):
+        yield item
+    assert False, "Too many `anext` items requested"
+
+
+@sync
+@pytest.mark.parametrize(
+    "slicing", ((0,), (5,), (0, 20, 3), (5, 0, 1), (3, 50, 4)),
+)
+async def test_islice_exact(slicing):
+    """`isclice` consumes exactly as many items as needed"""
+    boundary = slice(*slicing) if len(slicing) > 1 else slice(0, slicing[0])
+    expected = list(range(boundary.stop)[boundary])
+    assert (
+        await a.list(
+            a.islice(ayield_exactly(max(boundary.start, boundary.stop)), *slicing)
+        )
+        == expected
+    )
+
+
 starmap_cases = [
     (lambda x, y: x + y, [(1, 2), (3, 4)]),
     (lambda *args: sum(args), [range(i) for i in range(1, 10)]),

islice consumes too many items
The ``stop`` condition of ``islice`` is evaluated by *peeking* at the next item, then discarding it:

https://github.com/maxfischer2781/asyncstdlib/blob/7d45d075877433a2effb0b3aa9ec949816b892ac/asyncstdlib/itertools.py#L213-L217

This results in two undesirable behaviours:
- if the next item is available, it is discarded. Consecutive use of ``islice`` drops items.
- if the next item is not available, ``isclice`` blocks indefinitely.
unittests/test_itertools.py::test_islice_exact[slicing0] unittests/test_itertools.py::test_islice_exact[slicing1] unittests/test_itertools.py::test_islice_exact[slicing2] unittests/test_itertools.py::test_islice_exact[slicing3] unittests/test_itertools.py::test_islice_exact[slicing4]
unittests/test_itertools.py::test_accumulate unittests/test_itertools.py::test_accumulate_default unittests/test_itertools.py::test_accumulate_misuse unittests/test_itertools.py::test_cycle unittests/test_itertools.py::test_chain[iterables0] unittests/test_itertools.py::test_chain[iterables1] unittests/test_itertools.py::test_chain[iterables2] unittests/test_itertools.py::test_compress[data0-selectors0] unittests/test_itertools.py::test_compress[data1-selectors1] unittests/test_itertools.py::test_compress[data2-selectors2] unittests/test_itertools.py::test_compress[data3-selectors3] unittests/test_itertools.py::test_dropwhile[iterable0-<lambda>] unittests/test_itertools.py::test_dropwhile[iterable1-<lambda>] unittests/test_itertools.py::test_dropwhile[iterable2-<lambda>] unittests/test_itertools.py::test_dropwhile[iterable3-<lambda>] unittests/test_itertools.py::test_dropwhile[iterable4-<lambda>] unittests/test_itertools.py::test_dropwhile[iterable5-<lambda>] unittests/test_itertools.py::test_takewhile[iterable0-<lambda>] unittests/test_itertools.py::test_takewhile[iterable1-<lambda>] unittests/test_itertools.py::test_takewhile[iterable2-<lambda>] unittests/test_itertools.py::test_takewhile[iterable3-<lambda>] unittests/test_itertools.py::test_takewhile[iterable4-<lambda>] unittests/test_itertools.py::test_takewhile[iterable5-<lambda>] unittests/test_itertools.py::test_islice[slicing0-iterable0] unittests/test_itertools.py::test_islice[slicing0-iterable1] unittests/test_itertools.py::test_islice[slicing0-iterable2] unittests/test_itertools.py::test_islice[slicing0-iterable3] unittests/test_itertools.py::test_islice[slicing1-iterable0] unittests/test_itertools.py::test_islice[slicing1-iterable1] unittests/test_itertools.py::test_islice[slicing1-iterable2] unittests/test_itertools.py::test_islice[slicing1-iterable3] unittests/test_itertools.py::test_islice[slicing2-iterable0] unittests/test_itertools.py::test_islice[slicing2-iterable1] unittests/test_itertools.py::test_islice[slicing2-iterable2] unittests/test_itertools.py::test_islice[slicing2-iterable3] unittests/test_itertools.py::test_islice[slicing3-iterable0] unittests/test_itertools.py::test_islice[slicing3-iterable1] unittests/test_itertools.py::test_islice[slicing3-iterable2] unittests/test_itertools.py::test_islice[slicing3-iterable3] unittests/test_itertools.py::test_islice[slicing4-iterable0] unittests/test_itertools.py::test_islice[slicing4-iterable1] unittests/test_itertools.py::test_islice[slicing4-iterable2] unittests/test_itertools.py::test_islice[slicing4-iterable3] unittests/test_itertools.py::test_islice[slicing5-iterable0] unittests/test_itertools.py::test_islice[slicing5-iterable1] unittests/test_itertools.py::test_islice[slicing5-iterable2] unittests/test_itertools.py::test_islice[slicing5-iterable3] unittests/test_itertools.py::test_islice[slicing6-iterable0] unittests/test_itertools.py::test_islice[slicing6-iterable1] unittests/test_itertools.py::test_islice[slicing6-iterable2] unittests/test_itertools.py::test_islice[slicing6-iterable3] unittests/test_itertools.py::test_starmap[<lambda>-iterable0] unittests/test_itertools.py::test_starmap[<lambda>-iterable1] unittests/test_itertools.py::test_tee unittests/test_itertools.py::test_zip_longest unittests/test_itertools.py::test_groupby[keys-identity-iterable0] unittests/test_itertools.py::test_groupby[keys-identity-iterable1] unittests/test_itertools.py::test_groupby[keys-identity-iterable2] unittests/test_itertools.py::test_groupby[keys-identity-iterable3] unittests/test_itertools.py::test_groupby[keys-identity-iterable4] unittests/test_itertools.py::test_groupby[keys-modulo-iterable0] unittests/test_itertools.py::test_groupby[keys-modulo-iterable1] unittests/test_itertools.py::test_groupby[keys-modulo-iterable2] unittests/test_itertools.py::test_groupby[keys-modulo-iterable3] unittests/test_itertools.py::test_groupby[keys-modulo-iterable4] unittests/test_itertools.py::test_groupby[keys-divide-iterable0] unittests/test_itertools.py::test_groupby[keys-divide-iterable1] unittests/test_itertools.py::test_groupby[keys-divide-iterable2] unittests/test_itertools.py::test_groupby[keys-divide-iterable3] unittests/test_itertools.py::test_groupby[keys-divide-iterable4] unittests/test_itertools.py::test_groupby[values-identity-iterable0] unittests/test_itertools.py::test_groupby[values-identity-iterable1] unittests/test_itertools.py::test_groupby[values-identity-iterable2] unittests/test_itertools.py::test_groupby[values-identity-iterable3] unittests/test_itertools.py::test_groupby[values-identity-iterable4] unittests/test_itertools.py::test_groupby[values-modulo-iterable0] unittests/test_itertools.py::test_groupby[values-modulo-iterable1] unittests/test_itertools.py::test_groupby[values-modulo-iterable2] unittests/test_itertools.py::test_groupby[values-modulo-iterable3] unittests/test_itertools.py::test_groupby[values-modulo-iterable4] unittests/test_itertools.py::test_groupby[values-divide-iterable0] unittests/test_itertools.py::test_groupby[values-divide-iterable1] unittests/test_itertools.py::test_groupby[values-divide-iterable2] unittests/test_itertools.py::test_groupby[values-divide-iterable3] unittests/test_itertools.py::test_groupby[values-divide-iterable4]