JS 一次处理多个url请求

场景:使用工具函数downloadAllAsync接收一个URL数组并下载所有文件,结果返回一个存储了文件内容的数组,每个URL对应一个字符串。

好处:downloadAllAsync并不只有清理嵌套回调函数的好处,其主要好处是并行下载文件。我们可以在同一个事件循环中一次启动所有文件的下载,而不用等待每个文件完成下载。

并行逻辑是微妙的,很容易出错。下面的实现有一个隐蔽的缺陷。

function downloadAllAsync(urls, onsuccess, onerror) {
var result = [],
len = urls.length;

if(len === 0) { // 如果请求路径为空, 不执行下面的程序
// 绝不要同步地调用异步的回调函数
setTimeout(onsuccess.bind(null, result), 0);
return;
}

urls.foreach(function(url) {
downloadAsync(url, function(r) {
if(result) {
result.push(r); // race condition
// 根据提供的url, 所有文件数据被成功下载后,执行onsuccess程序
result.length === len && onsuccess(result);
}
}, function(e) {
if (result) {
result = null; // 在错误的情况下, 确保onerror只执行一次
onerror(e);
}
})
})
}


如果有多个下载失败,我们设置了result数组为null,从而保证onerror只被调用一次。即在第一次错误发生时。

downloadAllAsync函数实现的是一旦下载完成就立即将中间结果保存在result数组的末尾。因此,陷阱是保存下载文件内容的数组的顺序是未知的。几乎不能正确使用这样的API,因为调用者无法找出哪个结果对应哪个文件。

疑问:为什么使用setTimeout函数来调用onsuccess回调函数,而不是直接调用它

我们存储在原始的索引位置来提供预期结果

function downloadAllAsync(urls, onsuccess, onerror) {
var result = [],
len = urls.length;

if(len === 0) {
setTimeout(onsuccess.bind(null, result), 0);
return;
}

urls.foreach(function(url, index) {
downloadAsync(url, function(r) {
if(result) {
result[index] = r; // store at fixed index

result.length === len && onsuccess(result); // race condition
}
}, function(e) {
if (result) {
result = null;
onerror(e);
}
})
})
}


该实现利用了foreach回到函数的第二个参数。该参数为当前迭代提供的数组索引。不幸的是,这仍然不正确。

数组更新契约,即设置一个索引属性,总是确保数组的length属性大于索引。

正确的实现应用了一个计数器来追踪正在进行的操作数量。

function downloadAllAsync(urls, onsuccess, onerror) {
var result = [],
pending = urls.length;

if(pending === 0) {
setTimeout(onsuccess.bind(null, result), 0);
return;
}

urls.foreach(function(url, index) {
downloadAsync(url, function(r) {
if(result) {
result[index] = r; // store at fixed index
// pending -= 1; // register the success
// pending === 0 && onsuccess(result); // race condition

--padding || onsuccess(result);
}
}, function(e) {
if (result) {
result = null;
onerror(e);
}
})
})
}


现在整个世界都太平了,不论事情以什么样的顺序发生,pending计数器都能准确地指出何时所有的事件会被完成,并以预期的顺序返回完整的结果。

参考:编写高质量JS代码68个有效方法

时间: 2024-10-14 02:36:33

JS 一次处理多个url请求的相关文章

Nginx环境JS向PHP发送多个url请求跨域问题

Nginx配置: location ~ \.php$ { add_header Access-Control-Allow-Origin "*"; client_max_body_size 120m; fastcgi_pass    127.0.0.1:9000; include         fastcgi.conf; }

JS-获取URL请求参数

前言:原来做过一个项目,需要实现一个页面打印的功能,由于项目中使用了AngularJS+Bootstrap等前端框架,需要打印的页面又在弹出框中,使用了Bootstrap的模态框后发现打印的效果不太好,后来就使用原生的方式弹出一个新的窗口,不过新的窗口中的某些数据又需要从前一个页面中获取,使用AngularJS框架后发现从后台返回的页面总是被封装成一个对象,压根展现不了,怎么办?下面的这个小方法就是用于解决这个问题的——页面间跳转,在需要传递的参数不多的情况下,使用URL路径来传递参数.代码比较

js中ajax如何解决跨域请求

js中ajax如何解决跨域请求,在讲这个问题之前先解释几个名词 1.跨域请求 所有的浏览器都是同源策略,这个策略能保证页面脚本资源和cookie安全 ,浏览器隔离了来自不同源的请求,防上跨域不安全的操作. 跨域指的协议.域名.端口 有一个不同的情况下都是跨域 例:在本站点请求外站的数据是不允许的 //在本站点请求外站点的资源是不允许的 $(function () { $.ajax({ url: "http://127.0.0.1:14847/Web/jsonp.js", success

JS获取上一访问页面URL地址document.referrer实践2

一.JS获取前一个访问页面的URL地址document.referrer 要获取前一个访问页面的URL地址前后端语言都可以,例如PHP的是$_SERVER['HTTP_REFERER'],JavaScript的就是document.referrer. 我们平常开发,虽然和URL打交道也算比较频繁,但是,似乎很少使用document.referrer.我起初以为是兼容性不好,后来测试发现ie7都支持,那就奇怪了,为何document.referrer用的不多呢? 我想了一下,可能有下面几个原因:

SpringMVC(三)URL请求到Action的映射规则

在SpringMVC(二)经典的HelloWorld实现我们展示了一个简单的get请求,并返回了一个简单的helloworld页面.本篇我们来学习如何来配置一个action的url映射规则. 在SpringMVC(二)经典的HelloWorld实现我们在HelloWorldController上配置了一个@RequestMapping(value = "/helloworld")这表示对该controller的所有action请求必须是以"/helloworld"开

纳闷的url请求

今天对公司系统进行修改,还是ajax请求的问题,不过这次比上次的简单.但是遇到一个很纳闷的问题,我当时以为是ajax的问题,后来在浏览器上直接访问也是这样,连接就是这种:https://88.88.88.88:88/index.php?q=device/getdevictnum/did/88 问题描述:当我访问连接的did是40 ,就是url是 :https://114.104.206.14:28443/index.php?q=device/getdevictnum/did/40 的时候 访问正

springmvc中针对一个controller方法配置两个url请求

springmvc中针对一个controller方法配置两个url请求 标签: spring mvc孙琛斌 2015-12-10 17:10 2189人阅读 评论(0) 收藏 举报  分类: Spring(8)  版权声明:本文为博主原创文章,未经博主允许不得转载. 记录一个小知识点. 某些应用场景>..你可能需要不同的url请求得到相同的结果,那么你写两个方法总是不太好的,使用下面的方法可以解决这个问题. @RequestMapping(value = { "/item/index.ht

根据URL请求 返回XML字符串

public static string GetHttpResponse(string url) { string content = ""; // Create a new HttpWebRequest object.Make sure that // a default proxy is set if you are behind a fure wall. //其中,HttpWebRequest实例不使用HttpWebRequest的构造函数来创建,二是使用WebRequest的C

Objective-C中把URL请求的参数转换为字典

上一篇博客中是把URL转换为字典,那么我们如何把URL请求中的参数封装成字典,然后再封装成数组呢?对OC中字符串操作熟练的小伙伴们应该觉得这是一个a+b的问题,没错把URL中的参数转换为字典主要是对字符串的截取,关键是怎么个截法,才能把字符串中的参数列表分别转换成键值对.下面是小菜自己的转换思路,如果有更好的结局方法还请批评指正,相互学习交流一下,转载请注明出处. 首先我们得会一个字符串拆分函数 componentsSeparatedByString:@"&",把字符串按照&a