Javascript 在循环中使用承诺会导致承诺失败

Javascript 在循环中使用承诺会导致承诺失败,javascript,promise,Javascript,Promise,我希望在循环中重用相同的代码。此代码包含承诺。但是,迭代时,此代码会导致错误 我已经尝试使用进行和while循环。当我在单个迭代中使用for循环时,似乎没有问题 以下是我的代码的最低版本: var search_url = /* Some initial URL */ var glued = ""; for(var i = 0; i < 2; i++) { const prom = request(search_url) .then(function success(res

我希望在循环中重用相同的代码。此代码包含承诺。但是,迭代时,此代码会导致错误

我已经尝试使用
进行
while
循环。当我在单个迭代中使用
for
循环时,似乎没有问题

以下是我的代码的最低版本:

var search_url = /* Some initial URL */
var glued = "";
for(var i = 0; i < 2; i++)
{
    const prom = request(search_url)
    .then(function success(response /* An array from a XMLHTTPRequest*/) {
          if (/* Some condition */)
          {
              search_url = /* Gets next URL */
              glued += processQuery(response[0]);
          } else {
              console.log("Done.")
          }
    })
    .catch(function failure(err) {
          console.error(err.message); // TODO: do something w error
    })
}
document.getElementById('api-content').textContent = glued;


var search\u url=/*一些初始url*/
var glued=“”;
对于(变量i=0;i<2;i++)
{
const prom=请求(搜索url)
.then(函数成功(响应/*来自XMLHTTPRequest的数组*/){
如果(/*某些条件*/)
{
search_url=/*获取下一个url*/
glued+=processQuery(响应[0]);
}否则{
log(“完成”)
}
})
.catch(功能故障(err){
console.error(err.message);//TODO:执行带有错误的操作
})
}
document.getElementById('api-content')。textContent=glued;

我希望结果会附加到变量
glued
,但相反,我得到了一个错误:
failure Promise.catch(async)(匿名)
,在循环的第一次迭代之后。

您最好的选择可能是使用递归构建
glued
变量

下面是一个将递归与回调函数结合使用的示例:

var glued=“”;
递归请求(/*一些初始URL字符串*/,函数(){
document.getElementById('api-content')。textContent=glued;
});
递归请求函数(url、cb){
请求(url)。然后(函数(响应){
如果(/*某些条件*/){
glued+=processQuery(响应[0]);
var next=/*获取下一个URL字符串*/;
如果(下一个){
//有另一个URL。请发出另一个请求。
请求递归(下一步,cb);
}否则{
//我们完成了。调用回调;
cb();
}
}否则{
console.log(“完成”);
}
}).catch(函数(err){
控制台错误(错误消息);
});
}
回答: 您可以根据使用来执行承诺的异步执行。这可以打包成一个构造函数,在示例中它被称为
Serial
(因为我们要按顺序逐个检查承诺)

上面是什么

  • 它是一个名为
    Serial
    的构造函数
  • 它将返回承诺的函数数组作为参数
  • 这些函数存储在
    串行模式中。
  • 它有一个空数组存储在
    串行中。已解析
    -这将存储已解析的承诺请求
  • 它有两种方法:
    • addPromise
      :获取一个函数,该函数返回一个承诺并将其添加到
      Serial.promises
    • resolve
      :异步调用自定义
      符号。迭代器
      。这个
      迭代器
      遍历每一个承诺,等待它完成,并将其添加到
      Serial.resolved
      。完成后,它返回一个map函数,该函数作用于填充的
      Serial.resolved
      数组。这允许您只需调用
      resolve
      ,然后提供如何处理响应数组的回调。A.e.
      .resolve()((已解决的请求)=>//处理已解决的请求)
它为什么有效

虽然很多人没有意识到这个符号。迭代器对于循环来说比标准的
强大得多。这有两大原因

第一个原因,也是在这种情况下适用的原因,是因为允许异步调用,这会影响应用对象的状态

第二个原因是它可以用于提供来自同一对象的两种不同类型的数据。A.e.您可能有一个数组,希望读取以下内容:

let arr = [1,2,3,4];
您可以使用
for
循环或
forEach
获取数据:

arr.forEach(v => console.log(v)); 
// 1, 2, 3, 4
但如果调整迭代器:

arr[Symbol.iterator] = function* () {
  yield* this.map(v => v+1);
};
你得到这个:

arr.forEach(v => console.log(v));
// 1, 2, 3, 4
for(let v of arr) console.log(v);
// 2, 3, 4, 5
这对于许多不同的原因都很有用,包括时间戳请求/映射引用等。如果您想了解更多信息,请查看ECMAScript文档:


使用: 它可以通过使用返回承诺的函数数组调用构造函数来使用。您还可以通过使用向对象添加函数承诺

new Serial([])
.addPromise(() => fetch(url))
在使用
.resolve
方法之前,它不会运行函数

这意味着,在使用异步调用执行任何操作之前,如果愿意,可以添加临时承诺。A.e.这两者是相同的:

承诺:

 let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3)]); 
 promises.addPromise(() => fetch(url4));
 promises.resolve().then((responses) => responses)
 let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3), () => fetch(url4)])
.resolve().then((responses) => responses)
没有承诺:

 let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3)]); 
 promises.addPromise(() => fetch(url4));
 promises.resolve().then((responses) => responses)
 let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3), () => fetch(url4)])
.resolve().then((responses) => responses)

数据: 因为我不能真正复制您的数据调用,所以我选择了
JSONPlaceholder
(一个假的在线RESTAPI)来显示实际的承诺请求

数据如下所示:

let searchURLs = ["https://jsonplaceholder.typicode.com/todos/1", 
"https://jsonplaceholder.typicode.com/todos/2", 
"https://jsonplaceholder.typicode.com/todos/3"]

//since our constructor takes functions that return promises, I map over the URLS:
.map(url => () => fetch(url));
要获得响应,我们可以使用构造函数调用上述数据:

let promises = new Serial(searchURLS)
                .resolve()
                .then((resolved_array) => console.log(resolved_array));
我们的
resolved_数组
为我们提供了一个XHR响应对象数组。你可以在这里看到:

函数序列(承诺=[]){
返回{
承诺,
已解决:[],
附加承诺:功能(fn){
承诺推动(fn);
},
解析:异步函数(cb=i=>i,err=(e)=>console.log(“trace:Serial.resolve”+e)){
试一试{
对于wait(设这个[Symbol.iterator]())的p{}
返回此.resolved.map(cb);
}捕获(e){
错误(e);
}
},
[符号.迭代器]:异步函数*(){
此参数为[];
为了(让我们承诺这个。承诺){
让p=wait promise().catch(e=>console.log(“trace:Serial[Symbol.iterator]::”+e));
这个。解析。推(p);
产量p;
}
}
}
}
让searchURL=[”https://jsonplaceholder.typicode.com/todos/1", "https://jsonplaceholder.typicode.com/todos/2", "https://jsonplaceholder.typicode.com/todos/3“].map(url)