首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使嵌套循环仅在异步函数解析后才继续,或者如何将".then“扩展到作用域之外

如何使嵌套循环仅在异步函数解析后才继续,或者如何将".then“扩展到作用域之外
EN

Stack Overflow用户
提问于 2019-04-23 01:28:58
回答 3查看 223关注 0票数 2

在下面的代码中,我试图防止promises出现异步问题。通过使用.then函数,该函数中的所有内容都会在函数解析后被调用。但现在我遇到了一个问题:我既不能将".then函数“的范围扩展到足以包含第二个循环之后的位,也不能根据我的知识轻松地暂停代码,直到函数被正确解析,然后继续循环迭代。

以下是我的主要代码(简化):

代码语言:javascript
复制
let total = []
$.each(element, function(data) {
  //Some other code
  let out;
  $.each(element2, function(data2) {
    getZip(data2).then(function(txt){ //after everything has finished this get's called
      out = someFunction(txt,data2);
      total.push(out);
    });

  )};
   console.log(total)//this gets called first 
  //some other code that does some stuff with total
)};

下面是异步的getZip代码:

代码语言:javascript
复制
        function getZip(zipFile) {
            return new Promise(function (resolve, reject){
                zip = new JSZip()
                JSZipUtils.getBinaryContent("someURL/" + zipFile, function (err, data) {
                    if (err) {
                        reject(err)
                    }
                    JSZip.loadAsync(data).then(function (zip) {
                        return zip.file(zipFile.replace(".zip", "")).async("text"); //gets the file within the zip andoutputs as text
                    }).then(function (txt) {
                        resolve(txt)
                    });

                });
            });
        }

如果getZip代码可以同步,或者前面提到的都可以完成,我会很高兴。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-04-23 02:15:07

我想我没有完全理解你写的代码。但是,我建议您使用Promise.all。下面是我写的一个例子,希望能对你有所帮助:

代码语言:javascript
复制
let total = [];
$.each([1,2,3,4], function (data) {
  // Some other code.
  let out;
  // Create a new promise so that we can wait on the getZip method.
  new Promise(function (resolve, reject) {  
    // Create a holder variable. This variable with hold all the promises that are output from the getZip method you have.
    let gZipPromises = [];
    $.each([5,6,7,8], function (data2) {    
      // Your getZip method would go here. wrap the call to getZip in gZipPromises.push to push all the returned promises onto the holding variable.
      gZipPromises.push(new Promise(function (resolve2, reject2) { 
        // Sample Code
        setTimeout(function () {
         total.push(data2); 
          resolve2(""); 
        }, 10);
        // End Sample Code.
      }));
    });  
    // Pass the holding variable to Promise.all so that all promises in the holding variable are executed before resolving.
    Promise.all(gZipPromises).then(function() { 
      resolve() 
    });
  }).then(function () {
    // This will be called only when all getZip promises are completed in the second loop.
    console.log(total);
  });
});
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

话虽如此,我还是无法测试你的代码。但我认为这样做是可行的:(请注意,根据您提供的代码,将为最顶层的$.each的每次迭代记录变量total

代码语言:javascript
复制
let total = []
$.each(element, function(data) {
  //Some other code
  let out;  
  // Define a new promise.
  new Promise(function (resolve, reject) {
    let gZipPromises = [];
    $.each(element2, function(data2) {
      gZipPromises.push(
        getZip(data2).then(function(txt){ //after everything has finished this get's called
          out = someFunction(txt,data2);
          total.push(out);
        });
      );
    )};
    Promise.all(gZipPromises).then(function() { 
      resolve() 
    });
  }).then(function () { 
    console.log(total)
  });  
)};

票数 0
EN

Stack Overflow用户

发布于 2019-04-23 02:44:08

代码语言:javascript
复制
const elements = [["foo.zip"],["bar.zip"],["baz.zip"]];
const totalOut = getAllZips(elements)
  .then(text => console.info(text))
  .catch(error => console.error(error))

function someFunction(text, data) {
  return `${text}\nLength: ${data.length}`;
}

async function getAllZips(elements) {
  let promises = [];
  for(const element of elements) {
    for(const data of element) {
      promises.push(getZip(data).then(text => {
        return someFunction(text, data);
      }));
    }
  }
  return Promise.all(promises);
}

async function getZip(file) {
  return new Promise((resolve, reject) => {
    JSZipUtils.getBinaryContent(`someURL/${file}`, async (err, data) => {
      try {
        if (err) throw err;
        const zip = await JSZip.loadAsync(data);
        const name = file.replace(".zip", "");
        resolve(await zip.file(name).async('text'));
      } catch(error) {
        reject(error);
      }
    });
  });
}
代码语言:javascript
复制
<script>/*IGNORE*/const JSZipUtils = {getBinaryContent:(p,c)=>errs.gbc?c(new Error('gbc'),null):c(null,{foo:true})};const JSZip = {loadAsync:(d)=>errs.la?Promise.reject(new Error('la')):({file:n=>({async:a=>errs.a?Promise.reject(new Error('a')):Promise.resolve('Hello World')})})};const errs = {gbc:false,la:false,a:false};/*IGNORE*/</script>

票数 0
EN

Stack Overflow用户

发布于 2019-04-23 03:26:01

这听起来像是异步迭代器生成器的用例,但也许我只是过度设计了。您有一堆要迭代的资源,它们的内容是异步的。你希望它“看起来”同步,这样你就可以利用async/await:

代码语言:javascript
复制
function getZip(zipFile) {
  /*
   * Theres no point in simplifying this function since it looks like
   * the JSZip API deals with callbacks and not Promises.
   */
  return Promise.resolve(zipFile);
}

function someFn(a, b) {
  return `${a}: ${b.length}`;
}

async function* zipper(elements) {
  for (const element of elements) {
    for (const data of element) {
      const txt = await getZip(data);
      yield someFn(txt, data);
    }
  }
}

(async() => {
  const elements = [
    ["hello"],
    ["world"],
    ["foo"],
    ["bar"]
  ];
  let total = [];
  for await (const out of zipper(elements)) {
    total.push(out);
  }
  console.log(total);
})();

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55798396

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档