Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么我的承诺数组在调用Promise.all()之前运行?_Javascript_Promise - Fatal编程技术网

Javascript 为什么我的承诺数组在调用Promise.all()之前运行?

Javascript 为什么我的承诺数组在调用Promise.all()之前运行?,javascript,promise,Javascript,Promise,我试图创建一个承诺数组,然后用Promise.all()解析它们。我正在使用got,它返回一个承诺 我的代码可以工作,但我不完全理解如何工作。这是: const got = require('got'); const url = 'myUrl'; const params = ['param1', 'param2', 'param3']; let promiseArray = []; for (param of params) { promiseArray.push(got(url

我试图创建一个承诺数组,然后用Promise.all()解析它们。我正在使用got,它返回一个承诺

我的代码可以工作,但我不完全理解如何工作。这是:

const got = require('got');

const url = 'myUrl';
const params = ['param1', 'param2', 'param3'];

let promiseArray = [];
for (param of params) {
    promiseArray.push(got(url + param));
}

// Inspect the promises
for (promise of promiseArray) {
    console.log(JSON.stringify(promise));
    // Output: promise: {"_pending":true,"_canceled":false,"_promise":{}}
}

Promise.all(promiseArray).then((results) => {
     // Operate on results - works just fine
}).catch((e) => {
    // Error handling logic
});
让我感到不快的是,当我将承诺添加到数组中时,它们被标记为“待定”,这意味着它们已经开始了

我认为它们应该在
promiseArray
中处于非活动状态,并且
Promise.all(promiseArray)
将启动它们并解决它们


这是否意味着我要开始两次呢?

你不会开始两次。承诺一经创建就开始运行,或者一旦JS引擎找到足够的资源来启动它们。你无法控制它们何时真正开始


所有的
Promise.All()
所做的就是等待它们全部解决(解决或拒绝)
Promise.all()
不会干扰或影响承诺本身的执行顺序/时间

承诺根本不起作用。它们只是一个通知系统,用于在异步操作完成时进行通信

所以,一旦你运行这个:

promiseArray.push(got(url + param));
您在
get()
中的异步操作已经启动,当它完成时,它将通过promise将该操作返回

所有的
Promise.All()
所做的就是监视所有的承诺,并告诉您第一个承诺何时被拒绝或所有承诺何时都成功完成。它不会以任何方式“控制”异步操作。相反,您启动异步操作,它们通过承诺进行通信。您可以控制何时启动异步操作,异步操作从那时起自行运行


如果您将代码分解为若干部分,下面是每一部分中发生的情况:

let promiseArray = [];
for (param of params) {
    promiseArray.push(got(url + param));
}
这会调用
got()
多次,以启动该函数中的任何异步操作
got()
可能返回一个promise对象,然后将其放入您的
promiseArray
。因此,在这一点上,异步操作都已经启动并自行运行

// Inspect the promises
for (promise of promiseArray) {
    console.log(JSON.stringify(promise));
    // Output: promise: {"_pending":true,"_canceled":false,"_promise":{}}
}
这个循环只是查看所有的承诺,看看是否有任何承诺已经得到了解决,尽管人们并不期望它们得到解决,因为它们的底层异步操作刚刚在前面的循环中启动

Promise.all(promiseArray).then((results) => {
     // Operate on results - works just fine
}).catch((e) => {
    // Error handling logic
});
然后,使用
Promise.all()
,您只需要监视承诺数组,这样它就会告诉您何时有拒绝的承诺或何时所有承诺都成功完成。

承诺在创建时“启动”,即提供承诺的函数已启动(通常是异步的)最终将导致异步结果的操作。例如,如果函数返回HTTP请求结果的承诺,则它在返回承诺对象时已启动该HTTP请求

无论您对promise对象做了什么或没有做什么,该函数(
get
)已经创建了一个回调函数,并将其传递给异步API,例如HTTP请求/响应API。在该回调函数中(除非您检查
get
)的源代码,否则不会看到该函数),一旦该API调用该函数,承诺就会得到解决。在HTTP请求示例中,API使用HTTP响应调用特定回调,然后所述回调函数解析承诺


考虑到所有这些,将承诺视为“开始”或“运行”的东西有点奇怪。它们只是在待决状态下创建的。剩下的是来自某个API的挂起回调,该回调有望发生,然后将更改promise对象的状态,从而触发
然后
回调。

请注意,获取带有promise的URL数组。all可能存在一些问题:

  • 如果任何URL无法获取解析,则永远不会调用解析(因此 其中一个失败,您的resolve函数永远不会被调用
  • 如果您的阵列非常大,您的站点和网络将受到请求的冲击,您可能需要限制在特定时间段内发出的最大打开请求和/或请求
  • 第一个问题很容易解决,您可以处理失败的请求并将其添加到结果中。在解决处理程序中,您可以决定如何处理失败的请求:

    const got = require('got');
    
    const url = 'myUrl';
    const params = ['param1', 'param2', 'param3'];
    
    const Fail = function(details){this.details = details;};
    Promise.all(
      params.map(
        param =>
          got(url + param)
          .then(
            x=>x,//if resolved just pass along the value
            reject=>new Fail([reject,url+param])
          )
      )
    ).then((results) => {
      const successes = results.filter(result=>(result && result.constructor)!==Fail),
      const failedItems = results.filter(result=>(result && result.constructor)===Fail);
    }).catch((e) => {
        // Error handling logic
    });
    
    第2点有点复杂,节流可以通过以下方式完成:

    ... other code
    const max5 = throttle(5);
    Promise.all(
      params.map(
        param =>
          max5(got)(url + param)
          .then(
            x=>x,//if resulved just pass along the value
            reject=>new Fail([reject,url+param])
          )
      )
    )
    

    假设我没有调用Promise.all(),这是否意味着承诺将在promiseArray中自行解决/失败?因此,一段时间后,我将拥有一个已解决/失败的承诺数组?没错!每个承诺将只运行一次,然后保留其最终状态(已解决或已拒绝)你可以在将来的任何时候检查它,只要你在作用域中还有承诺对象或者在它上面有闭包。@alexcs-这个答案是非常误导的。承诺不会“运行”,也不会“启动”。它们只是坐在那里什么也不做的对象,直到其他异步操作通过调用
    resolve()
    reject()告诉它们做些什么
    关于它们。承诺只是一个通知系统。请参阅我的答案,以获得更准确的技术解释。@jfriend00我认为通俗地说,我们指的是承诺所代表的异步操作。即“承诺所代表的异步操作”开始运行…@ArashMotamedi-我不认为这是“理解的”他们显然非常困惑什么在运行,什么不在运行,什么承诺实际上是什么。纠正这一点是回答和明确实际发生的事情的一个重要部分。谢谢,第一个问题实际上是我很快就要优化的问题。