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;
}
请注意,这两种算法都被编码为不会延迟第一次操作,因为