javascript - js最好怎么在兩個(gè)AJax異步操作之后執(zhí)行一個(gè)新的操作
問(wèn)題描述
今天碰到一個(gè)面試問(wèn)題,就是如果頁(yè)面中有兩個(gè)異步ajax的操作,因?yàn)椴淮_定這兩個(gè)異步操作的執(zhí)行順序,怎么在這兩個(gè)操作都執(zhí)行完再執(zhí)行一個(gè)新的操作,最好的方法是什么?
我當(dāng)時(shí)回答了方法一:嵌套兩個(gè)ajax,在第二個(gè)ajax的返回函數(shù)中執(zhí)行新的操作。面試官回復(fù):這種方法太矬了。
于是想了下回答方法二:通過(guò)定時(shí)器setTimeout監(jiān)聽(tīng)局部變量,確保兩個(gè)異步操作執(zhí)行完了再執(zhí)行新操作。 面試官回復(fù):這種方式性能不好,能不能想到一個(gè)簡(jiǎn)單又更合理的方法。
當(dāng)時(shí)思考未果所以把這個(gè)問(wèn)題放上來(lái)尋求最好的方法是什么?歡迎討論指點(diǎn)
問(wèn)題解答
回答1:1.Promise 包裝異步ajax操作,2.定義async 函數(shù),3.用await等待promise數(shù)據(jù)異步獲取完成這一種方法簡(jiǎn)潔高效,下面請(qǐng)看我專門給你寫的示例代碼我懶得用ajax獲取數(shù)據(jù)了,就用settimeout這個(gè)函數(shù)模擬獲取數(shù)據(jù)吧,這個(gè)函數(shù)是異步的,原理效果一樣。
//模擬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}//等待兩個(gè)ajax異步操作執(zhí)行完了后執(zhí)行的方法const myFunction = async function() { const x = await ajax1() const y = await ajax2()//等待兩個(gè)異步ajax請(qǐng)求同時(shí)執(zhí)行完畢后打印出數(shù)據(jù) console.log(x, y)}myFunction()回答2:
http://api.jquery.com/jQuery....
回答3:目前瀏覽器環(huán)境中開(kāi)箱即用的原生方法是 Promise.all。
以調(diào)用我的地圖庫(kù) Sinomap Demo 為例,這個(gè)頁(yè)面中為了加載一張地圖,需要多個(gè)同時(shí)發(fā)起但不能確保返回順序的請(qǐng)求:
中國(guó)地形數(shù)據(jù)
各省份數(shù)值 JSON 數(shù)據(jù)
多種圖表疊加時(shí)多種圖表存在多種 JSON 數(shù)據(jù)需通過(guò)不同數(shù)據(jù)接口返回……
解決方法直接在未打包的 http://sinomap.ewind.us/demo/demo.js 中,示例:
// 封裝地形 GeoJSON 數(shù)據(jù)接口// 將每個(gè)數(shù)據(jù)接口封裝為一個(gè)返回 Promise 的函數(shù)function getArea () { return new Promise((resolve, reject) => { fetch(’./resources/china.json’).then(resp => resp.json().then(china => resolve(china)) ) })}// 封裝分色地圖數(shù)據(jù)接口function getPopulation () { return new Promise((resolve, reject) => { fetch(’./resources/china-population.json’).then(resp => resp.json().then(data => resolve(data)) ) })}// 封裝城市數(shù)據(jù)接口function getCity () { return new Promise((resolve, reject) => { fetch(’./resources/city.json’).then(resp => resp.json().then(data => resolve(data)) ) })}// 使用 Promise.all 以在三個(gè)數(shù)據(jù)接口均異步成功后,執(zhí)行回調(diào)邏輯Promise.all([getArea(), getPopulation(), getCity()]).then(values => { // 依次從返回的數(shù)據(jù)接口數(shù)組中獲取不同接口數(shù)據(jù) let china = values[0] let population = values[1] let city = values[2] // 使用數(shù)據(jù) doWithData(china, population, city)})
這樣通過(guò) Promise 不僅實(shí)現(xiàn)了回調(diào)邏輯的解耦,還實(shí)現(xiàn)了基礎(chǔ)的異步流程控制。
回答4:剛剛看到j(luò)query 的 when 方法,所以給你重寫了一個(gè),不一定有jquery的那么好,但至少能實(shí)現(xiàn)效果了,可以在控制臺(tái)直接輸入下述代碼試試,我勒個(gè)去,寫了我整整半小時(shí)。。
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:
問(wèn)下能不能用jQ,能用的話直接:
$.when($.ajax('page1'), $.ajax('page2')).done(function(){});
順帶給個(gè)$.when的文檔參考
回答6:我覺(jué)得是Promise的方法 all還是什么的
回答7:你的問(wèn)題是有三件事 a,b,c。c要在a和b結(jié)束之后再執(zhí)行。
有很多方法: 比如你說(shuō)的嵌套法 還有暴力監(jiān)聽(tīng)法
這個(gè)問(wèn)題我曾經(jīng)考慮過(guò),以下是我的解答。
異步發(fā)射器
用數(shù)組保存如何執(zhí)行異步操作注意里面的函數(shù)都有個(gè)參數(shù) commit ,它是一個(gè)函數(shù) 用來(lái)回傳值。 當(dāng)ajax成功的時(shí)候 把返回值回傳進(jìn)去就好
// 兩個(gè)異步操作 var todos = [ function getUser(commit){ setTimeout(() => { commit({ // 這里是異步結(jié)束的時(shí)候 利用 commit 把值回傳 name: ’eczn’,age: 20 }, 233); }); }, function getLoc(commit){setTimeout(() => { commit({area: ’某個(gè)地方’ });}, 333); }]; 編寫發(fā)射器
processors 是 todos 這樣的數(shù)據(jù)。 cb 是最終回調(diào)。
function launcher(processors, cb){ var o = {}; var count = 0; if (processors.length === 0) cb(o); processors.forEach((func, idx) => {func(function commit(asyncVal){ // 這就是commit函數(shù) // 把 asyncVal 的所有屬性合并到 o 上 // ( 利用 Object.keys 獲取對(duì)象全部屬性名 ) Object.keys(asyncVal).forEach(key => {o[key] = asyncVal[key]; }); // 計(jì)數(shù)器自加 count++; // 如果發(fā)射器全部發(fā)射完畢則調(diào)用回調(diào)函數(shù) cb 并把 o 作為參數(shù)傳遞 if (count === processors.length) cb(o); }); }); }并發(fā)他們
執(zhí)行異步發(fā)射器 并提供 最終回調(diào)
launcher(todos, function(whereEczn){ // todos 里面存放的異步操作的值由 commit 回調(diào)返回 // 全部回調(diào)跑完的時(shí)候 就會(huì)執(zhí)行當(dāng)前這段函數(shù) 并把期望值返回 console.log(whereEczn); // 按順序輸出 [’name’, ’area’].forEach(key => {console.log(`${key}: ${whereEczn[key]}`); }); });
https://eczn.coding.me/blog/%...
回答8:可以定義個(gè)變量a=0,ajax請(qǐng)求成功后在回調(diào)里設(shè)置a++;然后在兩個(gè)回調(diào)中均判斷下a==2 執(zhí)行操作函數(shù)
回答9:設(shè)置兩個(gè)flag,然后兩個(gè)ajax調(diào)用同一個(gè)回調(diào),在這個(gè)回調(diào)中判斷兩個(gè)flag都為true才執(zhí)行后續(xù)操作。
回答10:把a(bǔ)jax寫在另一個(gè)ajax里面再在回調(diào)那里執(zhí)行
相關(guān)文章:
1. boot2docker無(wú)法啟動(dòng)2. android - E/dalvikvm: Could not find class java.nio.file.Path,3. 請(qǐng)問(wèn)一下各位老鳥 我一直在學(xué)習(xí)獨(dú)孤九賤 現(xiàn)在是在tp5 今天發(fā)現(xiàn) 這個(gè)系列視頻沒(méi)有實(shí)戰(zhàn)4. tp6 事務(wù)閉包操作問(wèn)題5. docker-compose 為何找不到配置文件?6. ddos - apache日志很多其它網(wǎng)址,什么情況?7. JavaScript如何循序漸進(jìn),有效的學(xué)習(xí)?看不下去怎么辦?8. 使用uuid,并不能利用mysql的索引,有什么解決辦法?9. python - linux怎么在每天的凌晨2點(diǎn)執(zhí)行一次這個(gè)log.py文件10. mysql數(shù)據(jù)庫(kù)每次查詢是一條線程嗎?
