微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

forEach 循环的行为很奇怪,被调用的函数值记录在循环结束而不是期间

如何解决forEach 循环的行为很奇怪,被调用的函数值记录在循环结束而不是期间

编辑:目前我认为这个问题是 forEach 没有承诺意识到。 https://zellwk.com/blog/async-await-in-loops/

我正在尝试应用一个节点 javascript 翻译函数(我把它放在帖子的末尾,因为它很长)来循环遍历一组值。但是,当我出于某种原因循环时,我只会在循环完成后显示循环函数的某些部分:请允许我更清楚地说明这一点:

array = [["hello","hello" ],["my","my",],["name","name" ],["is","my" ],["joe","joe"]]

function process (item,index){
   
const translate = require('@vitalets/google-translate-api');
      
      console.log('loopaction'); //this shows that the loop is executing
    translate(item[0],{to: 'sp'}).then(result => {
    console.log(result.text);
  
}).catch(err => {
    console.error(err);
})


array.forEach(process);   // Applying the function process to the array in a ForEach loop

从这里我得到

循环动作 循环动作 循环动作 循环动作 循环动作

你好 米 名词 es 乔

因此似乎在允许显示值之前 forEach 循环已完成。这是我真的不明白的事情,因为数组值被正确转换,然后以正确的顺序注销。仿佛它们已经存储在内存中以备后用。然后在 forEach 循环顺序结束时调用

翻译函数如下所示:

function translate(text,opts,gotopts) {
opts = opts || {};
gotopts = gotopts || {};
var e;
[opts.from,opts.to].forEach(function (lang) {
    if (lang && !languages.isSupported(lang)) {
        e = new Error();
        e.code = 400;
        e.message = 'The language \'' + lang + '\' is not supported';
    }
});
if (e) {
    return new Promise(function (resolve,reject) {
        reject(e);
    });
}

opts.from = opts.from || 'auto';
opts.to = opts.to || 'en';
opts.tld = opts.tld || 'com';

opts.from = languages.getCode(opts.from);
opts.to = languages.getCode(opts.to);

var url = 'https://translate.google.' + opts.tld;
return got(url,gotopts).then(function (res) {
    var data = {
        'rpcids': 'MkEWBc','f.sid': extract('fdrFJe',res),'bl': extract('cfb2h','hl': 'en-US','soc-app': 1,'soc-platform': 1,'soc-device': 1,'_reqid': Math.floor(1000 + (Math.random() * 9000)),'rt': 'c'
    };

    return data;
}).then(function (data) {
    url = url + '/_/TranslateWebserverUi/data/batchexecute?' + querystring.stringify(data);
    gotopts.body = 'f.req=' + encodeURIComponent(JSON.stringify([[['MkEWBc',JSON.stringify([[text,opts.from,opts.to,true],[null]]),null,'generic']]])) + '&';
    gotopts.headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

    return got.post(url,gotopts).then(function (res) {
        var json = res.body.slice(6);
        var length = '';

        var result = {
            text: '',pronunciation: '',from: {
                language: {
                    didYouMean: false,iso: ''
                },text: {
                    autoCorrected: false,value: '',didYouMean: false
                }
            },raw: ''
        };

        try {
            length = /^\d+/.exec(json)[0];
            json = JSON.parse(json.slice(length.length,parseInt(length,10) + length.length));
            json = JSON.parse(json[0][2]);
            result.raw = json;
        } catch (e) {
            return result;
        }

        if (json[1][0][0][5] === undefined) {
            // translation not found,Could be a hyperlink?
            result.text = json[1][0][0][0];
        } else {
            json[1][0][0][5].forEach(function (obj) {
                if (obj[0]) {
                    result.text += obj[0];
                }
            });
        }
        result.pronunciation = json[1][0][0][1];

        // From language
        if (json[0] && json[0][1] && json[0][1][1]) {
            result.from.language.didYouMean = true;
            result.from.language.iso = json[0][1][1][0];
        } else if (json[1][3] === 'auto') {
            result.from.language.iso = json[2];
        } else {
            result.from.language.iso = json[1][3];
        }

        // Did you mean & autocorrect
        if (json[0] && json[0][1] && json[0][1][0]) {
            var str = json[0][1][0][0][1];

            str = str.replace(/<b>(<i>)?/g,'[');
            str = str.replace(/(<\/i>)?<\/b>/g,']');

            result.from.text.value = str;

            if (json[0][1][0][2] === 1) {
                result.from.text.autoCorrected = true;
            } else {
                result.from.text.didYouMean = true;
            }
        }

        return result;
    }).catch(function (err) {
        err.message += `\nUrl: ${url}`;
        if (err.statusCode !== undefined && err.statusCode !== 200) {
            err.code = 'BAD_REQUEST';
        } else {
            err.code = 'BAD_NETWORK';
        }
        throw err;
    });
});
}

我意识到有一种承诺格式,我遇到的问题可能与函数的异步性以及承诺需要多长时间才能得到解决有关。我似乎无法弄清楚为什么在我的 forEach 函数完全循环后,承诺没有解决显示,但它似乎以正确的顺序正确保存。很奇怪。

关于使这种情况发生的函数 translate() 有什么想法吗?无论如何,我是否可以重写我的函数 process () 以确保在继续之前转换函数已解析 promise 并且函数 process () 中的 .then() 已完全执行?

解决方法

您是对的,您正在使用 Promise,因此 translate() 将在执行其余代码时异步运行(在后台)。这就是为什么您在 translate 函数返回之前遍历所有 foreach() 的原因,从而获得该输出。

但是,在 async 函数或 promise 块中使用 forEach 循环也存在问题。不等待回调函数。因此,promise 链被破坏,导致意外行为。 不要在 promise 或 async 函数中使用 forEach 循环。相反,使用 for 循环遍历数组的项:

要避免这些问题,请将 forEach 循环更改为 For 循环并像这样使用 asyncawait

async function process (item,index){
    const translate = require('@vitalets/google-translate-api');
    console.log('loopaction'); //this shows that the loop is executing
    await translate(item[0],{to: 'sp'})
    .then(result => {
        console.log(result.text);
    })
    .catch(err => {
        console.error(err);
    })
}

async function main() {
    array = [["hello","hello" ],["my","my" ],["name","name" ],["is",["joe","joe"]]
    
    for (let i = 0; i < array.length; i++) {
        await process(array[i],i);
    }
}

main()

await 使函数等待直到 promise 被解决。

注意:您尝试使用 object.sleep() 创建超时,这在 javascript 中不存在,请改用 setTimeout(),请参阅:Sleep() in Javascript

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。