在JavaScript中的for循环中调用异步函数

在JavaScript中的for循环中调用异步函数,javascript,asynchronous,for-loop,closures,Javascript,Asynchronous,For Loop,Closures,我有以下代码: for(var i = 0; i < list.length; i++){ mc_cli.get(list[i], function(err, response) { do_something(i); }); } 但是很明显,这仍然总是使用for循环索引的最后一个值 我还尝试在for循环之前声明一个函数,如下所示: var create_closure = function(i) { return function() {

我有以下代码:

for(var i = 0; i < list.length; i++){
    mc_cli.get(list[i], function(err, response) {
        do_something(i);
    });
}
但是很明显,这仍然总是使用for循环索引的最后一个值

我还尝试在for循环之前声明一个函数,如下所示:

var create_closure = function(i) {
    return function() {
        return i;
    }
}
然后打电话

do_something(create_closure(i)())
但同样没有成功,返回值始终是for循环的最后一个值


谁能告诉我闭包有什么不对吗?我想我理解了它们,但我不明白为什么这不起作用。

因为您正在运行一个数组,您可以简单地使用
forEach
,它提供列表项和回调中的索引。迭代将有自己的范围

list.forEach(function(listItem, index){
  mc_cli.get(listItem, function(err, response) {
    do_something(index);
  });
});

您非常接近,但应该将闭包传递给
get
,而不是将其放入回调中:

function createCallback(i) {
    return function(){
        do_something(i);
    }
}


for(var i = 0; i < list.length; i++){
    mc_cli.get(list[i], createCallback(i));
}
函数createCallback(i){
返回函数(){
做点什么(我);
}
}
对于(变量i=0;i
这是异步函数内部循环范例,我通常使用立即调用的匿名函数来处理它。这可以确保使用正确的索引变量值调用异步函数

好的,很好。因此,所有异步函数都已启动,循环退出。现在,由于这些函数的异步性质,不知道它们将在什么时候完成,也不知道它们将以什么顺序完成。如果您的代码需要等到所有这些函数都完成后才能执行,我建议您简单地计算完成了多少函数:

var total = parsed_result.list.length;
var count = 0;

for(var i = 0; i < total; i++){
    (function(foo){
        mc_cli.get(parsed_result.list[foo], function(err, response) {
            do_something(foo);
            count++;
            if (count > total - 1) done();
        });
    }(i));
}

// You can guarantee that this function will not be called until ALL of the
// asynchronous functions have completed.
function done() {
    console.log('All data has been loaded :).');
}
var total=parsed_result.list.length;
var计数=0;
对于(变量i=0;i总计-1)完成();
});
}(i) );
}
//您可以保证在所有
//异步函数已经完成。
函数完成(){
log('所有数据都已加载:);
}

我知道这是一个旧线程,但无论如何,添加我的答案。ES2015
let
具有在每次迭代时重新绑定循环变量的功能,因此它在异步回调中保持循环变量的值,因此您可以尝试以下方法:

for(let i = 0; i < list.length; i++){
    mc_cli.get(list[i], function(err, response) {
        do_something(i);
    });
}
for(设i=0;i

但无论如何,最好使用
forEach
或使用立即调用的函数创建闭包,因为
let
是ES2015的特性,可能不支持所有浏览器和实现。从
Bindings->let->for/for-in-loop迭代范围下,我可以看到它在Edge 13甚至Firefox 49之前都不受支持(我没有在这些浏览器中检查)。它甚至说Node 4不支持它,但我个人测试过,它似乎得到了支持

如果希望在循环中运行异步函数,但在执行回调后仍希望保留索引或其他变量,则可以将代码包装在IIFE(立即调用的函数表达式)中

var arr=['Hello','World','Javascript','Async',':)'];
对于(变量i=0;i
使用
async/await
语法和
Promise

(async function() {
    for(var i = 0; i < list.length; i++){
        await new Promise(next => {
            mc_cli.get(list[i], function(err, response) {
                do_something(i); next()
            })
        })
    }
})()
(异步函数(){
对于(变量i=0;i{
mc_cli.get(列表[i],函数(错误,响应){
做某事(i);下一步
})
})
}
})()
这将停止每个循环中的循环,直到使用ES6(typescript)触发
next()
函数。您可以利用
async
wait
的优点:

let list: number[] = [1, 2, 3, 4, 5];

// this is async fucntion
function do_something(counter: number): Promise<number> {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('called after ' + counter + ' seconds');
            resolve(counter);
        }, counter * 1000);
    })
}
async function foo() {
    // itrate over list and wait for when everything is finished
    let data = await Promise.all(list.map(async i => await do_something(i)));

    console.log(data);
}

foo();
let list:number[]=[1,2,3,4,5];
//这是异步功能
功能做某事(计数器:数字):承诺{
返回新承诺((解决、拒绝)=>{
设置超时(()=>{
log('在'+counter+'秒之后调用');
解决(反);
},柜位*1000);
})
}
异步函数foo(){
//我把清单翻过来,等一切都完成了
让data=wait Promise.all(list.map(异步i=>wait do_something(i));
控制台日志(数据);
}
foo();

ES2017:您可以将异步代码封装在返回承诺(承诺中的异步代码)的函数(比如XHRPost)中

然后在for循环内调用函数(XHRPost),但使用神奇的wait关键字。:)

让http=newXMLHttpRequest();
让url为空http://sumersin/forum.social.json';
函数XHRpost(i){
返回新承诺(函数(解析){
让params='id=nobot&%3Aoperation=social%3AcreateForumPost&subject=Demo'+i+'&message=Here%20是%20Demo&'u charset=UTF-8';
http.open('POST',url,true);
http.setRequestHeader('Content-type','application/x-www-form-urlencoded');
http.onreadystatechange=函数(){
log(“完成”+i+“>”+http.readyState);
如果(http.readyState==4){
console.log('SUCCESS:',i);
解决();
}
}
http.send(params);
});
}
for(设i=1;i<5;i++){
等待XHRpost(i);
}
(异步函数(){
对于(变量i=1;i(async function() {
    for(var i = 0; i < list.length; i++){
        await new Promise(next => {
            mc_cli.get(list[i], function(err, response) {
                do_something(i); next()
            })
        })
    }
})()
let list: number[] = [1, 2, 3, 4, 5];

// this is async fucntion
function do_something(counter: number): Promise<number> {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('called after ' + counter + ' seconds');
            resolve(counter);
        }, counter * 1000);
    })
}
async function foo() {
    // itrate over list and wait for when everything is finished
    let data = await Promise.all(list.map(async i => await do_something(i)));

    console.log(data);
}

foo();
let http = new XMLHttpRequest();
let url = 'http://sumersin/forum.social.json';

function XHRpost(i) {
    return new Promise(function(resolve) {
        let params = 'id=nobot&%3Aoperation=social%3AcreateForumPost&subject=Demo' + i + '&message=Here%20is%20the%20Demo&_charset_=UTF-8';
        http.open('POST', url, true);
        http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        http.onreadystatechange = function() {
                console.log("Done " + i + "<<<<>>>>>" + http.readyState);
                if(http.readyState == 4){
                    console.log('SUCCESS :',i);
                    resolve();
                }
        }
        http.send(params);       
   });
}

for (let i = 1; i < 5; i++) {
    await XHRpost(i);
   }
(async function() {
  for(var i = 1; i < category.length; i++){

   let result = await $.ajax({
        url: '{{ route('admin.loyalty-commission.sub-category') }}', // Url of the Route
        
        data: {id:category[i-1], cat_state:i, next_cat:category[i]},
        success: function (data) {
            console.log('ajax success previous category id' + category[i-1]);

            // Check if the logic was successful or not
            if (data.status == 'success') {
                
                $(data.subcategories).appendTo(sub_category); //ajax result append to sub_category
            } else {
                console.log(data.msg);
            }
        },
        error: function (data) {
            // Error while calling the controller (HTTP Response Code different as 200 OK
            console.log('Error:', data);
            success = false;
        }
    });
 }
})()
 const refObjId= ['Account', 'Contact', 'Group'];

 const readdirPro = file => {
   return new Promise((resolve, reject) => {
    fs.readdir(file, (err, data) => {
      if (err) reject('I could not find the file');
      resolve(data);
    });
  });
};

const fileNamePromises = refObjId.map(async el => {
    const fileName = await readdirPro(`${__dirname}/../csv-files/${el}/data`);
    return fileName;
  });

//fileNamePromises is an array of promises


  const fileArr = await Promise.all(fileNamePromises);
    console.log(fileArr);