Javascript 简明教程
JavaScript - Async Iteration
Asynchronous Iteration
在 JavaScript 中,异步迭代是指遍历异步序列或集合的能力,例如异步函数或生成器返回的集合。异步迭代通常用于涉及异步任务的操作,例如从远程服务器获取数据或从文件读取数据。
In JavaScript, asynchronous iteration refers to the ability to iterate over asynchronous sequences or collections, such as those returned by asynchronous functions or generators. Async iteration is typically used with operations that involve asynchronous tasks, such as fetching data from a remote server or reading from a file.
Understanding Asynchronous Operations
简单来说,编程中的异步操作表示在等待完成期间不会阻塞程序执行的任务或过程。这些异步任务使程序能够继续执行其他职责,同时等待当前任务的完成,而不是在每个操作结束之前暂停,然后继续执行后续操作。
In basic terms, asynchronous operations in programming denote tasks or procedures that do not obstruct the program’s execution during their pending completion. Rather than pausing for each operation to conclude before proceeding onto the subsequent one; these asynchronous tasks enable a program: it continues executing other duties, concurrently waiting for the current task’s finalization.
Using the 'for await…of' Loop
for await…of 循环用于异步迭代。它的工作方式与常规的 for…of 循环类似,但它被设计为与异步迭代器一起工作。异步迭代器是一个定义了 async next() 方法的对象,该方法返回序列中下一个值的 Promise。
The for await…of loop is used for asynchronous iteration. It works similarly to the regular for…of loop, but it is designed to work with asynchronous iterators. An asynchronous iterator is an object that defines an async next() method, which returns a promise for the next value in the sequence.
Example: Using Promises
JavaScript 将 Promise 作为一种特性来管理异步操作;这些 Promise 表示异步任务的潜在结果,即完成或失败。值得注意的是,asyncOperation 函数通过返回 Promise 来模拟此类任务。for await…of 循环巧妙地浏览异步序列,强调在管理非阻塞操作时使用 Promise,同时不影响代码的清晰度。
JavaScript incorporates promises as a characteristic to manage asynchronous operations; these promises symbolize the potential outcomes, either completion or failure of an asynchronous task. Notably, the function asyncOperation emulates such tasks by returning a promise. The 'for await…of' loop elegantly navigates the asynchronous sequence, emphasizing promise utilization in managing non-blocking operations without compromising code lucidity.
<!DOCTYPE html>
<html>
<body>
<h2>Async Iteration with Promises</h2>
<div id="output"></div>
<script>
function asyncOperation(value) {
return new Promise(resolve => {
setTimeout(() => {
document.getElementById('output').innerHTML += `<p>Processed: ${value}</p>`;
resolve(value);
}, 1000);
});
}
const asyncIterable = {
[Symbol.asyncIterator]: async function* () {
for (let i = 1; i <= 3; i++) {
yield await asyncOperation(i);
}
},
};
async function processAsyncIterable() {
for await (const result of asyncIterable) {
document.getElementById('output').innerHTML += `<p>Received: ${result}</p>`;
}
}
processAsyncIterable();
</script>
</body>
</html>
Example 2: Using Fetch API for Asynchronous HTTP Requests
在这里,我们演示了使用 Fetch API 执行 HTTP 请求的异步迭代:asyncIterable 运行以异步方式获取数据。此外;使用 for await…of 循环,它优雅地遍历结果,展示了异步迭代如何与外部源数据检索无缝结合。
Here, we demonstrate asynchronous iteration with the Fetch API for executing HTTP requests: The asyncIterable operates to fetch data in an asynchronous manner. Furthermore; employing a 'for await…of' loop - it elegantly traverses through results showcasing how seamlessly async iteration amalgamates with external source data retrieval.
<!DOCTYPE html>
<html>
<body>
<h2>Async Iteration with Fetch API</h2>
<div id="output"></div>
<script>
const url = 'https://jsonplaceholder.typicode.com/todos/';
const asyncIterable = {
[Symbol.asyncIterator]: async function* () {
for (let i = 1; i <= 3; i++) {
const response = await fetch(`${url}${i}`);
const data = await response.json();
document.getElementById('output').innerHTML += `<p>Received: ${JSON.stringify(data)}</p>`;
yield data;
}
},
};
async function processAsyncIterable() {
for await (const result of asyncIterable) {
// Already displaying results above, no need for additional output.
}
}
processAsyncIterable();
</script>
</body>
</html>
Example 3: Using callback
该方法采用基于回调的机制来实现异步迭代。asyncOperation 函数模拟异步任务并在完成后回调。同时,processAsyncIterable 函数主动遍历数组,为每个元素调用异步操作。
The approach employs a callback-based mechanism to achieve asynchronous iteration. The function asyncOperation imitates an asynchronous task and calls back upon completion. Meanwhile, the processAsyncIterable function actively iterates through an array, invoking the asynchronous operation for every element.
<!DOCTYPE html>
<html>
<body>
<h2>Async Iteration with callback</h2>
<div id="output"></div>
<script>
function asyncOperation(value, callback) {
setTimeout(() => {
document.getElementById('output').innerHTML += `<p>Processed: ${value}</p>`;
callback(value);
}, 1000);
}
function processAsyncIterable(iterable, callback) {
const iterator = iterable[Symbol.iterator]();
function iterate() {
const next = iterator.next();
if (next.done) {
return;
}
const value = next.value;
asyncOperation(value, result => {
document.getElementById('output').innerHTML += `<p>Received: ${result}</p>`;
iterate();
});
}
iterate();
}
const asyncIterable = [5,6,7,8,9,10];
processAsyncIterable(asyncIterable, result => {
// You can handle final result or additional actions here if needed.
});
</script>
</body>
</html>
Example 4: Promise With Error
JavaScript 中的 .then() 方法使用一个或两个回调函数来管理 Promise 的成功解析:在 Promise 解析后,它执行其第一个函数;如果发生拒绝,则执行可选的第二个函数。
The method .then() in JavaScript employs one or two callback functions to manage the successful resolution of a Promise: upon the promise’s resolution, it executes its first function; should rejection occur – an optional second function is then executed.
The method .catch() accompanies Promises, specifically to address promise rejections. A single callback function executes upon the rejection of the promise; this provides an elegant solution for managing errors in asynchronous operations - eliminating the need for a distinct .then() block dedicated to error handling.
<!DOCTYPE html>
<html>
<head>
<style>
#output {
margin-top: 20px;
}
</style>
</head>
<body>
<h2>Async Iteration with Promises</h2>
<button onclick="startAsyncIteration()">Start Async Iteration</button>
<div id="output"></div>
<script>
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function fetchData(index) {
return new Promise((resolve, reject) => {
if (index < 5) {
delay(1000).then(() => resolve(`Data ${index}`));
} else {
// Simulate an error for index 5
reject(new Error('Error fetching data for index 5'));
}
});
}
function startAsyncIteration() {
document.getElementById('output').innerHTML = '';
let index = 0;
function iterate() {
fetchData(index)
.then(data => {
displayData(data);
index++;
if (index < 6) {
iterate();
}
})
.catch(error => {
// Display error on the page.
displayError(error.message);
});
}
iterate();
}
function displayData(data) {
const outputDiv = document.getElementById('output');
outputDiv.innerHTML += `<p>Data received: ${data}</p>`;
}
function displayError(errorMessage) {
const outputDiv = document.getElementById('output');
outputDiv.innerHTML += `<p style="color: red;">Error: ${errorMessage}</p>`;
}
</script>
</body>
</html>
Real World Use Cases
在实际场景中,我们应用 JavaScript 异步迭代来优化各种异步操作:从 Web 应用程序中的多个 API 并发获取数据;处理实时更新,这对聊天系统很重要,执行批处理任务或需要大量资源的并行任务。此外,使用这种技术可以管理文件操作和流,以及处理交互式网页上的并发用户交互。其他应用包括动态加载内容到网页上的从 IoT 设备处理数据,这些也从异步迭代中受益匪浅,因为它们在处理复杂的任务管理(例如离线优先应用程序的数据同步)时需要非阻塞效率和响应能力。
In real-world scenarios, we apply JavaScript async iterations to optimize various asynchronous operations: fetching data concurrently from multiple APIs in web applications; processing real-time updates - a function critical for chat systems and executing batch tasks or parallel tasks that require intensive resources. Furthermore, managing file operations and streams is possible with this technique along with handling concurrent user interactions on interactive web pages. Other applications involve processing data from IoT devices dynamically loading content onto webpages, these too benefit greatly from the use of asynchronous iteration due to their need for non-blocking efficiency as well responsiveness when dealing with complex task management such as offline-first application’s data synchronization.