赞
踩
在现代Web开发中,与服务器进行异步通信是常见的需求。然而,当需要同时发送多个请求时,如果不加以控制,可能会导致服务器负载过高,影响应用性能。本文将介绍如何使用Promise来控制请求的并发数,以确保请求能够有序地发送和处理,提高应用的效率和稳定性。
首先,异步编程是为了解决程序中耗时操作的执行问题。举个例子,假设你需要同时发送多个请求给服务器,等待它们都返回结果后再继续处理,但又不希望这些请求一个接一个地按顺序执行,因为这样会浪费时间。这时,我们可以利用Promise来控制请求的并发数,以提高效率。
Promise可以看作是一种表示异步操作结果的对象。它有两个重要的状态:进行中(pending)和已完成(fulfilled)或已拒绝(rejected)。当我们发送一个请求时,会创建一个对应的Promise对象,这个对象可以用来监听请求的结果。我们可以通过调用Promise的then方法,传入一个回调函数,在请求完成后执行相应的处理逻辑。
为了控制请求的并发数,我们可以设置一个计数器来记录当前正在进行的请求数量。当计数器小于并发数限制时,我们可以发送新的请求,计数器加1。当计数器达到并发数限制时,我们暂停发送新的请求,等待其中之一的请求完成,然后再继续发送下一个请求。这样就能保证同时发送的请求数量不超过设定的限制。
通过这种方式,我们可以合理地控制请求的并发数,避免对服务器造成过大的负荷,同时提高程序的执行效率。
总结起来,掌握Promise和异步编程的关键在于理解如何使用Promise对象来管理异步操作,利用计数器来控制并发数。这样我们就能更好地处理多个请求,提高应用的性能和稳定性。
并发(Concurrency)和并行(Parallelism)是计算机领域中常用的两个概念。
并发是指多个任务在同一个时间段内交替执行,它强调任务之间的交替执行和共享资源的竞争。在并发执行中,多个任务交替执行的顺序是不确定的,每个任务执行一段时间后,切换到下一个任务,通过快速的切换使得任务之间产生了一种同时进行的错觉。并发可以提高系统的吞吐量和响应性,但并不一定能够加速单个任务的执行速度。
并行是指多个任务同时进行,每个任务在不同的处理单元(如多个CPU核心)上执行。并行执行的任务之间相互独立,彼此之间不会产生竞争或依赖关系。通过并行执行,可以提高整体任务的处理能力,加速任务的执行速度。
并发控制(Concurrency Control)是指在并发执行的情况下,保证多个任务对共享资源的访问是正确和有序的。在并发环境中,多个任务可能同时访问和修改共享资源,如果不进行适当的控制,就会产生数据不一致、竞争条件和死锁等问题。并发控制的目标是通过采用合适的技术和策略,保证在多个任务同时执行时,对共享资源的访问和修改是安全和可靠的。
切片控制(Scheduling Control)是一种并发控制的策略,用于控制并发执行的任务按照一定的顺序和时间片长度进行切换。在多任务并发执行的情况下,切片控制决定了每个任务执行的时间片长度和切换的时机。通过合理的切片控制,可以平衡多个任务的执行,避免某个任务长时间占用资源而导致其他任务无法执行的情况。
切片控制通常涉及调度算法和调度器的设计和实现。调度算法决定了任务切换的策略,如先来先服务(First-Come, First-Served)、轮转(Round-Robin)、优先级调度等。调度器负责根据调度算法的策略,实现任务的切换和执行管理。
综上所述,并发和并行是不同的概念,而并发控制和切片控制则是在并发执行环境中保证任务执行的安全性和顺序性的技术手段。了解并理解这些概念对于处理多任务并发执行的场景非常重要。
// 设计一个函数,可以限制请求的并发,同时请求结束之后,调用callback函数 // sendRequest(requestList:,limits,callback) sendRequest( [()=>request('1'), ()=>request('2'), ()=>request('3'), ()=>request('4')], 3, //并发数 (res)=>{ console.log(res) }) // 其中request 可以是: function request (url,time=1){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('请求结束:'+url); if(Math.random() > 0.5){ resolve('成功') }else{ reject('错误;') } },time*1e3) }) }
为了实现请求的并发数控制,我们可以利用Promise和JavaScript的异步特性。下面是实现的步骤:
async function sendRequest(requestList, limits, callback) { const processRequest = async (request) => { // 执行请求的逻辑,这里使用console.log语句作为示例 console.log("Sending request:", request); // 模拟请求的异步执行 await new Promise((resolve) => setTimeout(resolve, 1000)); // 请求完成后调用回调函数 callback(request); }; // 创建一个计数器,用于限制并发请求数量 let counter = 0; // 并发控制函数 const controlConcurrency = async () => { while (counter < limits && requestList.length > 0) { const request = requestList.shift(); // 取出下一个请求 counter++; await processRequest(request); // 执行请求 counter--; } // 检查是否还有未完成的请求 if (counter === 0 && requestList.length === 0) { callback(); // 所有请求完成后调用回调函数 } }; // 启动并发控制 for (let i = 0; i < limits; i++) { controlConcurrency(); } } // 请求列表 const requestList = ["request1", "request2", "request3", "request4", "request5"]; // 并发限制数 const limits = 2; // 回调函数 const callback = (request) => { console.log("Request completed:", request); }; // 发送请求 sendRequest(requestList, limits, callback);
Promise.race
方法:与Promise.all
相反,Promise.race
方法可以在一组请求中任何一个请求完成时就触发回调函数,这可以用于实现更实时的响应。可以在控制并发请求的循环中使用Promise.race
来等待最快完成的请求,并处理其结果。请注意,每个优化方式的适用性取决于具体的使用场景和要求。根据实际情况选择适合的优化方式,可以有效提升代码的性能和用户体验。
function sendRequest(requestList, limits, callback) { const processRequest = async (request) => { console.log("Sending request:", request); await new Promise((resolve) => setTimeout(resolve, 1000)); return request; }; const requests = requestList.map((request) => processRequest(request)); const sendLimitedRequests = async () => { while (requests.length > 0) { const limitedRequests = requests.splice(0, limits); const fastestPromise = Promise.race(limitedRequests); const result = await fastestPromise; callback(result); // 请求完成后调用回调函数 } callback(); // 所有请求完成后调用回调函数 }; sendLimitedRequests().catch((error) => { console.error("Error occurred:", error); }); }
代码解释:
processRequest
,用于执行单个请求的逻辑。在这个示例中,使用 console.log
来模拟实际的请求,然后使用 setTimeout
来模拟异步请求的延迟,并返回请求本身作为结果。map
方法映射为执行请求的 Promise,并将这些 Promise 存储在 requests
数组中。sendLimitedRequests
,用于控制并发请求的数量。requests
数组是否还有待处理的请求。splice
方法从 requests
数组中截取 limits
个请求,形成一个新的数组 limitedRequests
,表示当前限制的请求数量。Promise.race
方法,传入 limitedRequests
数组,返回最先完成的 Promise(即最快完成的请求)。await
等待最快完成的请求的结果,并将结果保存在 result
变量中。callback
,将请求的结果传递给回调函数。requests
数组中的所有请求都被处理完毕。callback
,此时传递的参数为空,表示所有请求都已完成。sendLimitedRequests
函数时,使用 catch
方法捕获可能发生的错误,并将错误信息打印到控制台。总结来说,这段代码通过限制并发请求数量,并利用 Promise.race
方法等待最快完成的请求,实现了对一组请求的控制和处理,并在请求完成后调用回调函数进行进一步的处理
// 假设已有一个连接池对象 connectionPool,包含了可用连接的队列 function sendRequest(requestList, limits, callback) { const processRequest = async (request) => { console.log("Sending request:", request); await new Promise((resolve) => setTimeout(resolve, 1000)); return request; }; const sendLimitedRequests = async () => { while (requestList.length > 0) { const limitedRequests = requestList.splice(0, limits); const promises = limitedRequests.map((request) => processRequest(request)); const results = await Promise.all(promises); results.forEach((result) => { callback(result); // 请求完成后调用回调函数 }); } callback(); // 所有请求完成后调用回调函数 }; sendLimitedRequests().catch((error) => { console.error("Error occurred:", error); }); }
代码解释:
processRequest
,用于执行单个请求的逻辑。在这个示例中,使用 console.log
来模拟实际的请求,然后使用 setTimeout
来模拟异步请求的延迟,并返回请求本身作为结果。sendLimitedRequests
,用于控制并发请求的数量。requestList
数组是否还有待处理的请求。splice
方法从 requestList
数组中截取 limits
个请求,形成一个新的数组 limitedRequests
,表示当前限制的请求数量。map
方法遍历 limitedRequests
数组,将每个请求传入 processRequest
函数中执行,返回一个 Promise 数组 promises
。Promise.all
方法,传入 promises
数组,等待所有请求的 Promise 都完成,并将它们的结果保存在 results
数组中。forEach
方法遍历 results
数组,对每个请求的结果调用回调函数 callback
。requestList
数组中的所有请求都被处理完毕。callback
,此时传递的参数为空,表示所有请求都已完成。sendLimitedRequests
函数时,使用 catch
方法捕获可能发生的错误,并将错误信息打印到控制台。function sendRequest(requestList, limits, callback) { const processRequest = async (request) => { console.log("Sending request:", request); await new Promise((resolve) => setTimeout(resolve, 1000)); return request; }; const requestQueue = [...requestList]; const sendNextRequest = async () => { if (requestQueue.length === 0) { callback(); // 所有请求完成后调用回调函数 return; } const request = requestQueue.shift(); try { const result = await processRequest(request); callback(result); // 请求完成后调用回调函数 } catch (error) { console.error("Error occurred:", error); } finally { sendNextRequest(); // 处理下一个请求 } }; for (let i = 0; i < limits; i++) { sendNextRequest(); // 启动请求队列处理 } }
代码解释:
processRequest
,用于执行单个请求的逻辑。在这个示例中,使用 console.log
来模拟实际的请求,然后使用 setTimeout
来模拟异步请求的延迟,并返回请求本身作为结果。requestQueue
,使用展开运算符 ...
将 requestList
数组复制到请求队列中。sendNextRequest
,用于处理下一个请求。requestQueue
数组的长度,如果长度为 0,则表示所有请求已完成,调用回调函数 callback
,并返回。shift
方法从 requestQueue
中取出下一个请求。await
等待请求的完成。callback
,将请求结果传递给回调函数。catch
捕获错误并打印错误信息。finally
关键字确保 sendNextRequest
函数递归调用,处理下一个请求。for
循环,根据 limits
参数的值,多次调用 sendNextRequest
函数,启动请求队列的处理。总结来说,这段代码通过维护一个请求队列和递归调用的方式,实现了限制并发请求数量,并在请求完成后调用回调函数进行进一步的处理。它将请求的处理过程分散在多个异步函数中,并使用递归调用来处理下一个请求,直到所有请求都完成。
const requestCache = new Map(); function sendRequest(requestList, limits, callback) { const processRequest = async (request) => { console.log("Sending request:", request); // 检查缓存中是否存在请求结果 if (requestCache.has(request)) { console.log("Using cached result for request:", request); return requestCache.get(request); } // 执行请求的逻辑 const result = await new Promise((resolve) => setTimeout(() => { resolve(request); }, 1000)); // 将请求结果存入缓存 requestCache.set(request, result); return result; }; const sendLimitedRequests = async () => { while (requestList.length > 0) { const limitedRequests = requestList.splice(0, limits); const promises = limitedRequests.map(processRequest); const results = await Promise.all(promises); results.forEach((result) => { callback(result); // 请求完成后调用回调函数 }); } callback(); // 所有请求完成后调用回调函数 }; sendLimitedRequests().catch((error) => { console.error("Error occurred:", error); }); }
代码解释:
Map
对象 requestCache
用于缓存请求的结果。processRequest
,用于执行单个请求的逻辑。processRequest
函数中,首先检查缓存中是否已存在请求结果。如果缓存中存在请求结果,则直接返回缓存中的结果。setTimeout
模拟异步请求,并在 1 秒后将请求本身作为结果返回。requestCache
中,使用请求作为键,结果作为值。sendRequest
中,继续使用 sendLimitedRequests
函数来控制并发请求数量。requestList
数组是否还有待处理的请求。splice
方法从 requestList
数组中截取 limits
个请求,形成一个新的数组 limitedRequests
,表示当前限制的请求数量。map
方法遍历 limitedRequests
数组,将每个请求传入 processRequest
函数中执行,返回一个 Promise 数组 promises
。Promise.all
方法,传入 promises
数组,等待所有请求的 Promise 都完成,并将它们的结果保存在 results
数组中。forEach
方法遍历 results
数组,对每个请求的结果调用回调函数 callback
。requestList
数组中的所有请求都被处理完毕。callback
,此时传递的参数为空,表示所有请求都已完成。sendLimitedRequests
函数时,使用 catch
方法捕获可能发生的错误,并将错误信息打印到控制台。总结来说,这段代码在前面的基础上添加了请求结果的缓存功能,以减少重复请求,并在请求开始前先检查缓存中是否存在结果。这样可以提高性能和效率,特别是在请求重复发送的场景下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。