I encountered an interview question today, that is, if there are two asynchronous ajax operations on the page, because the execution order of the two asynchronous operations is not sure, how to execute a new operation after both operations are executed? What's the best approach?
I answered method one at that time: nest two ajaxes and perform new operations in the return function of the second ajax. Interviewer's reply: This method is too lame.
So I thought about the second answer: monitor local variables through the timer setTimeout, and ensure that the two asynchronous operations are completed before performing a new operation. Interviewer's reply: The performance of this method is not good. Can you think of a simple and more reasonable method?
Thoughts failed at the time
So I put this question up to find what is the best way? Welcome to discuss and give advice
1. Promise wraps asynchronous ajax operations,
2. Define async function,
3. Use await to wait for the asynchronous acquisition of promise data to be completed. This method is simple and efficient. Please see the sample code I wrote specifically for you below. I am too lazy to use it. After ajax obtains data, use the settimeout function to simulate obtaining data. This function is asynchronous and has the same principle and effect.
//模擬ajax異步操作1
function ajax1() {
const p = new Promise((resolve, reject) => {
setTimeout(function() {
resolve('ajax 1 has be loaded!')
}, 1000)
})
return p
}
//模擬ajax異步操作2
function ajax2() {
const p = new Promise((resolve, reject) => {
setTimeout(function() {
resolve('ajax 2 has be loaded!')
}, 2000)
})
return p
}
//等待兩個ajax異步操作執(zhí)行完了后執(zhí)行的方法
const myFunction = async function() {
const x = await ajax1()
const y = await ajax2()
//等待兩個異步ajax請求同時執(zhí)行完畢后打印出數(shù)據(jù)
console.log(x, y)
}
myFunction()
The current out-of-the-box native method in the browser environment is Promise.all.
Take calling my map library Sinomap Demo as an example. In order to load a map on this page, multiple requests are required to be initiated at the same time but the return order cannot be guaranteed:
China terrain data
JSON data of each province
When multiple charts are overlaid, there are multiple JSON data in multiple charts that need to be returned through different data interfaces...
The solution is directly in the unpackaged http://sinomap.ewind.us/demo/demo.js
, example:
// 封裝地形 GeoJSON 數(shù)據(jù)接口
// 將每個數(shù)據(jù)接口封裝為一個返回 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 以在三個數(shù)據(jù)接口均異步成功后,執(zhí)行回調邏輯
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)
})
In this way, Promise not only realizes the decoupling of callback logic, but also realizes basic asynchronous process control.
I just saw the when method of jquery, so I rewrote one for you. It may not be as good as jquery, but at least it can achieve the effect. You can directly enter the following code in the console to try. Let me go and write It took me half an hour. .
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);
});
Ask if I can use jQ. If so, just say:
$.when($.ajax("page1"), $.ajax("page2")).done(function(){});
By the way, here is a document reference for $.when
Your question is there are three things a, b, c. c should be executed after a and b are completed.
There are many methods: such as the nesting method you mentioned, and the violent monitoring method
I have thought about this question before, and here is my answer.
Asynchronous emitter
Note that the functions inside all have a parameter commit , which is a function used to return a value. When ajax succeeds, just pass the return value back in
// 兩個異步操作
var todos = [
function getUser(commit){
setTimeout(() => {
commit({ // 這里是異步結束的時候 利用 commit 把值回傳
name: 'eczn',
age: 20
}, 233);
});
},
function getLoc(commit){
setTimeout(() => {
commit({
area: '某個地方'
});
}, 333);
}
];
Processors are data like todos. cb is the final callback.
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 獲取對象全部屬性名 )
Object.keys(asyncVal).forEach(key => {
o[key] = asyncVal[key];
});
// 計數(shù)器自加
count++;
// 如果發(fā)射器全部發(fā)射完畢則調用回調函數(shù) cb 并把 o 作為參數(shù)傳遞
if (count === processors.length) cb(o);
});
});
}
Execute an asynchronous emitter and provide final callback
launcher(todos, function(whereEczn){
// todos 里面存放的異步操作的值由 commit 回調返回
// 全部回調跑完的時候 就會執(zhí)行當前這段函數(shù) 并把期望值返回
console.log(whereEczn);
// 按順序輸出
['name', 'area'].forEach(key => {
console.log(`${key}: ${whereEczn[key]}`);
});
});
https://eczn.coding.me/blog/%...
You can define a variable a=0, and set a++ in the callback after the ajax request is successful;
Then judge a==2 in both callbacks and execute the operation function
Set two flags, and then two ajax call the same callback. In this callback, it is judged that both flags are true before subsequent operations are performed.