javascript - js最好怎么在两个AJax异步操作之后执行一个新的操作
问题描述
今天碰到一个面试问题,就是如果页面中有两个异步ajax的操作,因为不确定这两个异步操作的执行顺序,怎么在这两个操作都执行完再执行一个新的操作,最好的方法是什么?
我当时回答了方法一:嵌套两个ajax,在第二个ajax的返回函数中执行新的操作。面试官回复:这种方法太矬了。
于是想了下回答方法二:通过定时器setTimeout监听局部变量,确保两个异步操作执行完了再执行新操作。 面试官回复:这种方式性能不好,能不能想到一个简单又更合理的方法。
当时思考未果所以把这个问题放上来寻求最好的方法是什么?欢迎讨论指点
问题解答
回答1:1.Promise 包装异步ajax操作,2.定义async 函数,3.用await等待promise数据异步获取完成这一种方法简洁高效,下面请看我专门给你写的示例代码我懒得用ajax获取数据了,就用settimeout这个函数模拟获取数据吧,这个函数是异步的,原理效果一样。
//模拟ajax异步操作1function ajax1() { const p = new Promise((resolve, reject) => {setTimeout(function() { resolve(’ajax 1 has be loaded!’)}, 1000) }) return p}//模拟ajax异步操作2function ajax2() { const p = new Promise((resolve, reject) => {setTimeout(function() { resolve(’ajax 2 has be loaded!’)}, 2000) }) return p}//等待两个ajax异步操作执行完了后执行的方法const myFunction = async function() { const x = await ajax1() const y = await ajax2()//等待两个异步ajax请求同时执行完毕后打印出数据 console.log(x, y)}myFunction()回答2:
http://api.jquery.com/jQuery....
回答3:目前浏览器环境中开箱即用的原生方法是 Promise.all。
以调用我的地图库 Sinomap Demo 为例,这个页面中为了加载一张地图,需要多个同时发起但不能确保返回顺序的请求:
中国地形数据
各省份数值 JSON 数据
多种图表叠加时多种图表存在多种 JSON 数据需通过不同数据接口返回……
解决方法直接在未打包的 http://sinomap.ewind.us/demo/demo.js 中,示例:
// 封装地形 GeoJSON 数据接口// 将每个数据接口封装为一个返回 Promise 的函数function getArea () { return new Promise((resolve, reject) => { fetch(’./resources/china.json’).then(resp => resp.json().then(china => resolve(china)) ) })}// 封装分色地图数据接口function getPopulation () { return new Promise((resolve, reject) => { fetch(’./resources/china-population.json’).then(resp => resp.json().then(data => resolve(data)) ) })}// 封装城市数据接口function getCity () { return new Promise((resolve, reject) => { fetch(’./resources/city.json’).then(resp => resp.json().then(data => resolve(data)) ) })}// 使用 Promise.all 以在三个数据接口均异步成功后,执行回调逻辑Promise.all([getArea(), getPopulation(), getCity()]).then(values => { // 依次从返回的数据接口数组中获取不同接口数据 let china = values[0] let population = values[1] let city = values[2] // 使用数据 doWithData(china, population, city)})
这样通过 Promise 不仅实现了回调逻辑的解耦,还实现了基础的异步流程控制。
回答4:刚刚看到jquery 的 when 方法,所以给你重写了一个,不一定有jquery的那么好,但至少能实现效果了,可以在控制台直接输入下述代码试试,我勒个去,写了我整整半小时。。
function ajax(callback){ callback = callback || function(){}; var xhr = new XMLHttpRequest(); xhr.open('get',''); xhr.onload = function(res){ callback(res) }; xhr.send(null); }var when = (function(){ var i = 0,len = 0,data = []; return function(array,callback){callback = callback || function(){}; len = len || array.length;var fn = array.shift(); fn(function(res){ i++; data.push(res); if(i < len){when(array,callback); } else {callback(data); }}); };})();when([ajax,ajax],function(data){ console.log(data);});回答5:
问下能不能用jQ,能用的话直接:
$.when($.ajax('page1'), $.ajax('page2')).done(function(){});
顺带给个$.when的文档参考
回答6:我觉得是Promise的方法 all还是什么的
回答7:你的问题是有三件事 a,b,c。c要在a和b结束之后再执行。
有很多方法: 比如你说的嵌套法 还有暴力监听法
这个问题我曾经考虑过,以下是我的解答。
异步发射器
用数组保存如何执行异步操作注意里面的函数都有个参数 commit ,它是一个函数 用来回传值。 当ajax成功的时候 把返回值回传进去就好
// 两个异步操作 var todos = [ function getUser(commit){ setTimeout(() => { commit({ // 这里是异步结束的时候 利用 commit 把值回传 name: ’eczn’,age: 20 }, 233); }); }, function getLoc(commit){setTimeout(() => { commit({area: ’某个地方’ });}, 333); }]; 编写发射器
processors 是 todos 这样的数据。 cb 是最终回调。
function launcher(processors, cb){ var o = {}; var count = 0; if (processors.length === 0) cb(o); processors.forEach((func, idx) => {func(function commit(asyncVal){ // 这就是commit函数 // 把 asyncVal 的所有属性合并到 o 上 // ( 利用 Object.keys 获取对象全部属性名 ) Object.keys(asyncVal).forEach(key => {o[key] = asyncVal[key]; }); // 计数器自加 count++; // 如果发射器全部发射完毕则调用回调函数 cb 并把 o 作为参数传递 if (count === processors.length) cb(o); }); }); }并发他们
执行异步发射器 并提供 最终回调
launcher(todos, function(whereEczn){ // todos 里面存放的异步操作的值由 commit 回调返回 // 全部回调跑完的时候 就会执行当前这段函数 并把期望值返回 console.log(whereEczn); // 按顺序输出 [’name’, ’area’].forEach(key => {console.log(`${key}: ${whereEczn[key]}`); }); });
Linkhttps://eczn.coding.me/blog/%...
回答8:可以定义个变量a=0,ajax请求成功后在回调里设置a++;然后在两个回调中均判断下a==2 执行操作函数
回答9:设置两个flag,然后两个ajax调用同一个回调,在这个回调中判断两个flag都为true才执行后续操作。
回答10:把ajax写在另一个ajax里面再在回调那里执行
相关文章:
1. dockerfile - 为什么docker容器启动不了?2. nignx - docker内nginx 80端口被占用3. 关docker hub上有些镜像的tag被标记““This image has vulnerabilities””4. 新手学习vue和node.js的困惑5. boot2docker无法启动6. docker 17.03 怎么配置 registry mirror ?7. docker - 各位电脑上有多少个容器啊?容器一多,自己都搞混了,咋办呢?8. 请问连接文件怎么写9. 求解答:访问不了虚拟服务器的问题?10. docker网络端口映射,没有方便点的操作方法么?