Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/447.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 承诺不返回期望值_Javascript_Node.js - Fatal编程技术网

Javascript 承诺不返回期望值

Javascript 承诺不返回期望值,javascript,node.js,Javascript,Node.js,我一直在学习承诺,我有一个问题。我有一个名为getNumber的函数,它返回一个数字数组(为了理解)。我使用该函数迭代该数组,并对每个值发出http请求(使用setTimeout在调用之间进行延迟) 然后我想使用Then函数中收集的信息,但它给了我一个“未定义的错误”。显然这里出了点问题,但我看不出来。你们知道我该怎么解决这个问题吗 var getNumbers = () => { return new Promise(function(resolve, reject) {

我一直在学习承诺,我有一个问题。我有一个名为
getNumber
的函数,它返回一个数字数组(为了理解)。我使用该函数迭代该数组,并对每个值发出http请求(使用
setTimeout
在调用之间进行延迟)

然后我想使用
Then
函数中收集的信息,但它给了我一个
“未定义的错误”
。显然这里出了点问题,但我看不出来。你们知道我该怎么解决这个问题吗

var getNumbers  = () => {
  return new Promise(function(resolve, reject) {

    console.log("In function getNumbers");
    var data = [1,2,3,4,5,6,7,8,9];
    resolve(data);
  });
};


getNumbers()

    .then(numbersArray => {
        //Supposed to return array of posts title
        return numbersArray.map(number => {
          console.log("Reading number" + number);

            setTimeout(() => {
                //make a http request
                return getHtml("https://jsonplaceholder.typicode.com/posts/"+number)
                    .then(function(post) {
                        return post.title;
                    })

            }, 10000);//make a request each ten seconds
        });
    })
    .then(postTitlesArray => {
    //Shows array of undefined
      console.log(postTitlesArray)

    });



function getHtml(webUrl) {
    return fetch(webUrl)
        .then(function(res) {
            return res.json();
        });
}

我假设您要做的是:1)使用
getNumbers
获取数字列表。2) 迭代第一步中的每个数字,形成一个url,每十秒钟使用该url发出一次http请求。3) 如果请求成功发送,请等待其响应。4) 从响应中获取
post.title
。5) 等待步骤2中的迭代结束,并返回从每个调用接收到的所有
post.titles
的数组

考虑到上述假设,我稍微编辑一下您的代码,下面的解决方案就可以了。再见

我认为代码的主要问题是
map
方法没有返回任何内容

const getNumbers  = () => {
  return new Promise(function(resolve, reject) {

    console.log("In function getNumbers");
    var data = [1,2,3,4,5,6,7,8,9];
    resolve(data);
  });
};

const delay = (number, t) => {
    return new Promise((resolve) => {
      setTimeout(() => { 
        //make a http request
        resolve(
          getHtml("https://jsonplaceholder.typicode.com/posts/"+number)
          .then(function(post) {
            console.log('title', post.title)
            return post.title;
          })
        )
      }, t)
    })

}

const getHtml = (webUrl) => {
    return fetch(webUrl)
        .then(function(res) {
            return res.json();
        });
}

getNumbers()
    .then(numbersArray => {
        //Supposed to return array of posts title
        return Promise.all(numbersArray.map((number, i) => {
          console.log("Reading number" + number);
          return delay(number, 10000*(i+1));//make a request each ten seconds
        }))
        .then(postTitlesArray => {
            console.log(postTitlesArray)
            });
    })

我假设您要做的是:1)使用
getNumbers
获取数字列表。2) 迭代第一步中的每个数字,形成一个url,每十秒钟使用该url发出一次http请求。3) 如果请求成功发送,请等待其响应。4) 从响应中获取
post.title
。5) 等待步骤2中的迭代结束,并返回从每个调用接收到的所有
post.titles
的数组

考虑到上述假设,我稍微编辑一下您的代码,下面的解决方案就可以了。再见

我认为代码的主要问题是
map
方法没有返回任何内容

const getNumbers  = () => {
  return new Promise(function(resolve, reject) {

    console.log("In function getNumbers");
    var data = [1,2,3,4,5,6,7,8,9];
    resolve(data);
  });
};

const delay = (number, t) => {
    return new Promise((resolve) => {
      setTimeout(() => { 
        //make a http request
        resolve(
          getHtml("https://jsonplaceholder.typicode.com/posts/"+number)
          .then(function(post) {
            console.log('title', post.title)
            return post.title;
          })
        )
      }, t)
    })

}

const getHtml = (webUrl) => {
    return fetch(webUrl)
        .then(function(res) {
            return res.json();
        });
}

getNumbers()
    .then(numbersArray => {
        //Supposed to return array of posts title
        return Promise.all(numbersArray.map((number, i) => {
          console.log("Reading number" + number);
          return delay(number, 10000*(i+1));//make a request each ten seconds
        }))
        .then(postTitlesArray => {
            console.log(postTitlesArray)
            });
    })

在你做你想做的事情的方法中有几个概念性的东西

首先,
.map()
是同步的。这意味着它一直运行到完成,不等待任何异步操作完成

其次,
setTimeout()
是非阻塞的。它只是在将来安排一段时间的计时器,然后您的
.map()
回调立即返回,不返回任何内容

所以,你的方法根本不起作用

从您的评论来看,您试图完成的似乎是在一个循环中进行一系列网络调用,但在它们之间设置一个延迟,这样您就不会受到速率限制。有很多方法可以做到这一点

您需要两个基本概念来实现这一点:

  • 使异步操作按顺序进行,以便在前一个异步操作完成之前不会启动下一个异步操作

  • 在开始下一个计划之前,先推迟一个符合承诺的计划

  • 我将首先展示使用
    async/await
    的ES7方法,因为它在概念上可能是最简单的

    使用
    async/await
    对异步阵列访问进行排序

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(async function(numbersArray) {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        for (let number of numbersArray) {
            console.log("Reading number" + number);
            let r = await delay(delayT).then(() => {
                delayT = 10 * 1000;   // 10 seconds for subsequent delays
                return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                    return post.title;
                });
            });
            results.push(r);
        }
        return results;
    });
    
    使用
    .reduce()
    对异步数组访问进行排序

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(async function(numbersArray) {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        for (let number of numbersArray) {
            console.log("Reading number" + number);
            let r = await delay(delayT).then(() => {
                delayT = 10 * 1000;   // 10 seconds for subsequent delays
                return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                    return post.title;
                });
            });
            results.push(r);
        }
        return results;
    });
    
    如果希望在不使用
    async/await
    的情况下执行此操作,则可以使用
    .reduce()
    设计模式对数组的异步迭代进行排序:

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(numbersArray => {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        return numersArray.reduce((p, number) => {
            return p.then(() => {
                return delay(delayT).then(() => {
                    delayT = 10 * 1000;   // 10 seconds for subsequent delays
                    return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                        results.push(post.title);
                    });
                });
            });
        }, Promise.resolve()).then(() => {
            // make array of results be the resolved value of the returned promise
            return results;
        });
    });
    
    // Iterate through an array in sequence with optional delay between each async operation
    // Returns a promise, resolved value is array of results
    async iterateArrayAsync(array, fn, opts = {}) {
        const options = Object.assign({
            continueOnError: true, 
            delayBetweenAsyncOperations: 0,
            errPlaceHolder: null
        }, opts);
        const results = [];
        let delayT = 0;      // no delay on first iteration
        for (let item of array) {
            results.push(await delay(delayT).then(() => {
                return fn(item);
            }).catch(err => {
                console.log(err);
                if (options.continueOnError) {
                    // keep going on errors, let options.errPlaceHolder be result for an error
                    return options.errPlaceHolder;
                } else {
                    // abort processing on first error, will reject the promise
                    throw err;
                }
            }));
            delayT = options.delayBetweenAsyncOperations;   // set delay between requests
        }
        return results;
    }
    
    请注意,这两种算法都被编码为不延迟第一个操作,因为您可能不需要延迟,所以它只在连续操作之间延迟


    按照编码,它们是按照
    Promise.all()
    建模的,如果您的
    getHtml()
    调用被拒绝,它们将被拒绝。如果要返回所有结果,即使某些结果被拒绝,也可以更改:

    return getHtml(...).then(...)
    

    对于任何失败的结果,这将在返回的数组中放入
    null
    ,或者如果您想记录错误,您可以使用:

    return getHtml(...).then(...).catch(err => {
        console.log(err);
        return null;
    });
    

    通用辅助功能

    而且,由于这是一个一般性的问题,因此这里有一个通用帮助函数,它允许您迭代一个数组,对数组中的每个项调用异步操作,并将所有结果累积到一个数组中:

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(numbersArray => {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        return numersArray.reduce((p, number) => {
            return p.then(() => {
                return delay(delayT).then(() => {
                    delayT = 10 * 1000;   // 10 seconds for subsequent delays
                    return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                        results.push(post.title);
                    });
                });
            });
        }, Promise.resolve()).then(() => {
            // make array of results be the resolved value of the returned promise
            return results;
        });
    });
    
    // Iterate through an array in sequence with optional delay between each async operation
    // Returns a promise, resolved value is array of results
    async iterateArrayAsync(array, fn, opts = {}) {
        const options = Object.assign({
            continueOnError: true, 
            delayBetweenAsyncOperations: 0,
            errPlaceHolder: null
        }, opts);
        const results = [];
        let delayT = 0;      // no delay on first iteration
        for (let item of array) {
            results.push(await delay(delayT).then(() => {
                return fn(item);
            }).catch(err => {
                console.log(err);
                if (options.continueOnError) {
                    // keep going on errors, let options.errPlaceHolder be result for an error
                    return options.errPlaceHolder;
                } else {
                    // abort processing on first error, will reject the promise
                    throw err;
                }
            }));
            delayT = options.delayBetweenAsyncOperations;   // set delay between requests
        }
        return results;
    }
    

    这接受允许您继续出错的选项,允许您设置每个异步操作之间的延迟,并允许您控制任何失败操作的结果数组中的占位符(仅当设置了
    continueOnError
    时使用)。所有的选项都是可选的。

    在你的方法中,有几个概念性的东西可以让你随心所欲

    首先,
    .map()
    是同步的。这意味着它一直运行到完成,不等待任何异步操作完成

    其次,
    setTimeout()
    是非阻塞的。它只是在将来安排一段时间的计时器,然后您的
    .map()
    回调立即返回,不返回任何内容

    所以,你的方法根本不起作用

    从您的评论来看,您试图完成的似乎是在一个循环中进行一系列网络调用,但在它们之间设置一个延迟,这样您就不会受到速率限制。有很多方法可以做到这一点

    您需要两个基本概念来实现这一点:

  • 使异步操作按顺序进行,以便在前一个异步操作完成之前不会启动下一个异步操作

  • 在开始下一个计划之前,先推迟一个符合承诺的计划

  • 我将首先展示使用
    async/await
    的ES7方法,因为它在概念上可能是最简单的

    使用
    async/await
    对异步阵列访问进行排序

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(async function(numbersArray) {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        for (let number of numbersArray) {
            console.log("Reading number" + number);
            let r = await delay(delayT).then(() => {
                delayT = 10 * 1000;   // 10 seconds for subsequent delays
                return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                    return post.title;
                });
            });
            results.push(r);
        }
        return results;
    });
    
    使用
    .reduce()
    对异步数组访问进行排序

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(async function(numbersArray) {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        for (let number of numbersArray) {
            console.log("Reading number" + number);
            let r = await delay(delayT).then(() => {
                delayT = 10 * 1000;   // 10 seconds for subsequent delays
                return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                    return post.title;
                });
            });
            results.push(r);
        }
        return results;
    });
    
    如果希望在不使用
    async/await
    的情况下执行此操作,则可以使用
    .reduce()
    设计模式对数组的异步迭代进行排序:

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    getNumbers().then(numbersArray => {
        //Supposed to return array of posts title
        let results = [];
        let delayT = 0;    // first delay is zero
        return numersArray.reduce((p, number) => {
            return p.then(() => {
                return delay(delayT).then(() => {
                    delayT = 10 * 1000;   // 10 seconds for subsequent delays
                    return getHtml("https://jsonplaceholder.typicode.com/posts/"+number).then(function(post) {
                        results.push(post.title);
                    });
                });
            });
        }, Promise.resolve()).then(() => {
            // make array of results be the resolved value of the returned promise
            return results;
        });
    });
    
    // Iterate through an array in sequence with optional delay between each async operation
    // Returns a promise, resolved value is array of results
    async iterateArrayAsync(array, fn, opts = {}) {
        const options = Object.assign({
            continueOnError: true, 
            delayBetweenAsyncOperations: 0,
            errPlaceHolder: null
        }, opts);
        const results = [];
        let delayT = 0;      // no delay on first iteration
        for (let item of array) {
            results.push(await delay(delayT).then(() => {
                return fn(item);
            }).catch(err => {
                console.log(err);
                if (options.continueOnError) {
                    // keep going on errors, let options.errPlaceHolder be result for an error
                    return options.errPlaceHolder;
                } else {
                    // abort processing on first error, will reject the promise
                    throw err;
                }
            }));
            delayT = options.delayBetweenAsyncOperations;   // set delay between requests
        }
        return results;
    }
    
    请注意,这两种算法都被编码为不会延迟第一次操作,因为