我使用 Promises 好吗?
Am I using Promises well?
问题
我的问题是我希望我的代码执行以下操作:
- 提出初始请求
- 一旦我得到那个请求的答案,我就会处理它并再次发出一批请求
- 完成批处理并获得所有响应后,我将编写一个文件
- 文件完成后,我打印一条消息
前两步我做对了,但我的程序没有按预期执行后两步。
代码
这段代码试图举例说明我想要实现的目标。只有 promise
and jsonfile
它是一个简单的应用程序,它详细地表示了我的代码的体系结构,并且它可以立即运行,前提是您安装了这两个库。
let jsonfile = require("jsonfile");
let Promise = require("promise");
let write = Promise.denodeify(jsonfile.writeFile);
let writeOutput = function(filename, content) {
return write(filename, content, {spaces: 4});
};
//Returns a random number each time it is invoked
//after a random period of time between 1s and 6s
let requestSimulator = function() {
return new Promise((fulfil, reject) => {
let randomNum = Math.random();
let wait = Math.floor((Math.random() * 6000) + 2000);
setTimeout(() => fulfil(randomNum), wait, randomNum);
});
};
//Returns an array of rounded numbers
let roundNumbers = function(someNumbers) {
let numbersArr = [];
let tmpNum;
for (let number of someNumbers) {
tmpNum = Math.floor(number);
console.log("Rounded " + number + " to " + tmpNum);
numbersArr.push(tmpNum);
}
return numbersArr;
};
//Receives an array of rounded numbers, and for each number
//makes a new request.
//It then sums the response with the given number.
let sumNumbersBatch = function(numbersArr) {
let promisesArray = [];
for (let number of numbersArr) {
let promise = new Promise((fulfil, reject) => {
requestSimulator()
.then(result => {
let newNum = number + result;
console.log("Summing " + number + " with " + result + "resultint in " + newNum);
fulfil(newNum);
});
});
promisesArray.push(promise);
}
return new Promise.all(promisesArray);
};
//Starts the process
let getData = function() {
return new Promise((fulfil, reject) => {
requestSimulator()
.then(number => fulfil([number, number * 2, number * 3]));
});
};
console.log("Starting program");
getData()
.then(roundNumbers)
.then(sumNumbersBatch)
.then(newNumbers => writeOutput("testFile.txt", newNumbers))
.then(console.log("Program finished"))
.catch(console.log);
在 运行 之后,您可以看到输出类似于:
Starting program
Program finished
Rounded 0.20890058801647582 to 0
Rounded 0.41780117603295164 to 0
Rounded 0.6267017640494275 to 0
Summing 0 with 0.05537663551196226resultint in 0.05537663551196226
Summing 0 with 0.34853429001859215resultint in 0.34853429001859215
Summing 0 with 0.988336787994851resultint in 0.988336787994851
错了!!!!
Program finish
应该出现在最后,而不是第二!
问题:
所以现在我对我的代码有疑问:
- 我是否正确使用了 Promise.all?
- 我承诺
write
功能好吗?
此外,我愿意接受有关代码质量的建议!!!!
任何帮助和解释将不胜感激。
我重写了整个答案以匹配修改后的代码。我第一次尝试 "answer" 只不过是对第一个提供的代码似乎有问题的扩展评论;所以什么都没有丢失。
你的大部分代码都是正确的,这一行实际上是 "wrong":
.then(console.log("Program finished"))
并让您感到困惑,因为它会立即调用 console.log("Program finished")
和 return undefined
,因此 then 会转换为 .then(undefined)
.
应该是
.then(() => console.log("Program finished"))
而且Promise.all()
前面应该有没有new
尽管可以改进一些事情,尤其是您对延迟反模式的使用。当您已经在那个地方处理承诺时,这就是在不需要时手动创建延迟对象。喜欢这个:
//Starts the process
let getData = function() {
return new Promise((fulfil, reject) => {
requestSimulator()
.then(number => fulfil([number, number * 2, number * 3]));
});
};
更好
//Starts the process
let getData = function() {
return requestSimulator().then(number => [number, number * 2, number * 3]);
};
而在 requestSimulator
中,您需要创建一个 new Promise()
才能将 Promises 与 setTimeout()
一起使用。那里是合适的。
let jsonfile = require("jsonfile");
let Promise = require("promise");
let write = Promise.denodeify(jsonfile.writeFile);
//OK, now this function has a purpose/additional value (formatting)
//and is not just forwarding the arguments
let writeOutput = function(filename, content) {
return write(filename, content, {spaces: 4});
};
//fine, a mock
let requestSimulator = function() {
return new Promise((fulfil, reject) => {
let randomNum = Math.random();
let wait = Math.floor((Math.random() * 6000) + 2000);
//there's no need/reason to pass `randomNum` to setTimeout as a third argument
setTimeout(() => fulfil(randomNum), wait);
});
};
//this can be shortened to, although it doesn't log anymore
let roundNumbers = function(someNumbers) {
return someNumbers.map(Math.floor);
};
//Receives an array of rounded numbers, and for each number
//makes a new request.
//It then sums the response with the given number.
let sumNumbersBatch = function(numbersArr) {
//this again can be achieved simpler by using `Array#map` instead of `for..of`
let promisesArray = numbersArr.map(number => {
return requestSimulator()
.then(result => result + number);
});
//no `new` here! Promise.all() is just a utility-function, no constructor.
return Promise.all(promisesArray);
};
//Starts the process
let getData = function() {
//removed the wrapping Promise.
return requestSimulator()
.then(number => [ number, number * 2, number * 3 ]);
};
console.log("Starting program");
getData()
.then(roundNumbers)
.then(sumNumbersBatch)
.then(newNumbers => writeOutput("testFile.txt", newNumbers))
//this executes `console.log()` immediately and passes the result (`undefined`) to `then()`
//.then(console.log("Program finished"))
//but `then()` needs a function:
.then(() => console.log("Program finished"))
//here you pass a reference to the function `console.log`, that's fine
.catch(console.log);
- 我是否正确使用了
Promise.all
?
是也不是,您使用 Promise.all
的方式很奇怪 - 您总是提供一个空数组。 Promise.all
期望作为输入的承诺数组,它等待输入中的所有承诺得到解决或其中任何一个失败。
它 returns 一个要么被解决(如果所有输入的承诺都正确)要么被拒绝(如果任何一个失败)的承诺。在你原来的情况下 Promise.all
总是被解决,因为输入列表是空的
- 我的文件是真的在所有请求完成后写入,还是在它们完成时写入?
方法writeOutput
在从makeBatchRequests
返回的Promise被解析后被调用,它是用两个参数调用的-fileName
,这是 undefined
因为它从未在您的代码中定义,第二个是 result
- 这是一个 Array
其成员是 promisesArray
的解析结果,它始终为空.所以从技术上讲,是的,该函数在所有请求完成后被调用,但是没有数据被写入文件(哦,实际上,空字符串""
是[].toString()
将打印到文件 :] )
- 我承诺写功能好吗?
是,你做对了。
除此之外,尝试重写您的代码,一步一步,在进行每一步时对其进行测试,并将预期结果与实际结果进行比较。
正如上面的答案中提到的,有很多东西需要修复,祝你好运! :]
那么,我认为问题可能出在 writeOutput(fileName, result)
,你确定 returns 是一个承诺吗?
这更像是一个建议,而不是实际答案,但请尝试这样做:
scrapy.getStanceMods()
.then(['www.google.com', 'www.reddit.com'])
.then(makeBatchRequest)
.then(result => {
return writeOutput(fileName, result))
.then(console.log("Completed."))
.catch(error=>console.log('will catch inner errors'))
})
.catch(error =>console.error(error));
问题
我的问题是我希望我的代码执行以下操作:
- 提出初始请求
- 一旦我得到那个请求的答案,我就会处理它并再次发出一批请求
- 完成批处理并获得所有响应后,我将编写一个文件
- 文件完成后,我打印一条消息
前两步我做对了,但我的程序没有按预期执行后两步。
代码
这段代码试图举例说明我想要实现的目标。只有 promise
and jsonfile
它是一个简单的应用程序,它详细地表示了我的代码的体系结构,并且它可以立即运行,前提是您安装了这两个库。
let jsonfile = require("jsonfile");
let Promise = require("promise");
let write = Promise.denodeify(jsonfile.writeFile);
let writeOutput = function(filename, content) {
return write(filename, content, {spaces: 4});
};
//Returns a random number each time it is invoked
//after a random period of time between 1s and 6s
let requestSimulator = function() {
return new Promise((fulfil, reject) => {
let randomNum = Math.random();
let wait = Math.floor((Math.random() * 6000) + 2000);
setTimeout(() => fulfil(randomNum), wait, randomNum);
});
};
//Returns an array of rounded numbers
let roundNumbers = function(someNumbers) {
let numbersArr = [];
let tmpNum;
for (let number of someNumbers) {
tmpNum = Math.floor(number);
console.log("Rounded " + number + " to " + tmpNum);
numbersArr.push(tmpNum);
}
return numbersArr;
};
//Receives an array of rounded numbers, and for each number
//makes a new request.
//It then sums the response with the given number.
let sumNumbersBatch = function(numbersArr) {
let promisesArray = [];
for (let number of numbersArr) {
let promise = new Promise((fulfil, reject) => {
requestSimulator()
.then(result => {
let newNum = number + result;
console.log("Summing " + number + " with " + result + "resultint in " + newNum);
fulfil(newNum);
});
});
promisesArray.push(promise);
}
return new Promise.all(promisesArray);
};
//Starts the process
let getData = function() {
return new Promise((fulfil, reject) => {
requestSimulator()
.then(number => fulfil([number, number * 2, number * 3]));
});
};
console.log("Starting program");
getData()
.then(roundNumbers)
.then(sumNumbersBatch)
.then(newNumbers => writeOutput("testFile.txt", newNumbers))
.then(console.log("Program finished"))
.catch(console.log);
在 运行 之后,您可以看到输出类似于:
Starting program
Program finished
Rounded 0.20890058801647582 to 0
Rounded 0.41780117603295164 to 0
Rounded 0.6267017640494275 to 0
Summing 0 with 0.05537663551196226resultint in 0.05537663551196226
Summing 0 with 0.34853429001859215resultint in 0.34853429001859215
Summing 0 with 0.988336787994851resultint in 0.988336787994851
错了!!!!
Program finish
应该出现在最后,而不是第二!
问题:
所以现在我对我的代码有疑问:
- 我是否正确使用了 Promise.all?
- 我承诺
write
功能好吗?
此外,我愿意接受有关代码质量的建议!!!!
任何帮助和解释将不胜感激。
我重写了整个答案以匹配修改后的代码。我第一次尝试 "answer" 只不过是对第一个提供的代码似乎有问题的扩展评论;所以什么都没有丢失。
你的大部分代码都是正确的,这一行实际上是 "wrong":
.then(console.log("Program finished"))
并让您感到困惑,因为它会立即调用 console.log("Program finished")
和 return undefined
,因此 then 会转换为 .then(undefined)
.
应该是
.then(() => console.log("Program finished"))
而且Promise.all()
new
尽管可以改进一些事情,尤其是您对延迟反模式的使用。当您已经在那个地方处理承诺时,这就是在不需要时手动创建延迟对象。喜欢这个:
//Starts the process
let getData = function() {
return new Promise((fulfil, reject) => {
requestSimulator()
.then(number => fulfil([number, number * 2, number * 3]));
});
};
更好
//Starts the process
let getData = function() {
return requestSimulator().then(number => [number, number * 2, number * 3]);
};
而在 requestSimulator
中,您需要创建一个 new Promise()
才能将 Promises 与 setTimeout()
一起使用。那里是合适的。
let jsonfile = require("jsonfile");
let Promise = require("promise");
let write = Promise.denodeify(jsonfile.writeFile);
//OK, now this function has a purpose/additional value (formatting)
//and is not just forwarding the arguments
let writeOutput = function(filename, content) {
return write(filename, content, {spaces: 4});
};
//fine, a mock
let requestSimulator = function() {
return new Promise((fulfil, reject) => {
let randomNum = Math.random();
let wait = Math.floor((Math.random() * 6000) + 2000);
//there's no need/reason to pass `randomNum` to setTimeout as a third argument
setTimeout(() => fulfil(randomNum), wait);
});
};
//this can be shortened to, although it doesn't log anymore
let roundNumbers = function(someNumbers) {
return someNumbers.map(Math.floor);
};
//Receives an array of rounded numbers, and for each number
//makes a new request.
//It then sums the response with the given number.
let sumNumbersBatch = function(numbersArr) {
//this again can be achieved simpler by using `Array#map` instead of `for..of`
let promisesArray = numbersArr.map(number => {
return requestSimulator()
.then(result => result + number);
});
//no `new` here! Promise.all() is just a utility-function, no constructor.
return Promise.all(promisesArray);
};
//Starts the process
let getData = function() {
//removed the wrapping Promise.
return requestSimulator()
.then(number => [ number, number * 2, number * 3 ]);
};
console.log("Starting program");
getData()
.then(roundNumbers)
.then(sumNumbersBatch)
.then(newNumbers => writeOutput("testFile.txt", newNumbers))
//this executes `console.log()` immediately and passes the result (`undefined`) to `then()`
//.then(console.log("Program finished"))
//but `then()` needs a function:
.then(() => console.log("Program finished"))
//here you pass a reference to the function `console.log`, that's fine
.catch(console.log);
- 我是否正确使用了
Promise.all
?
是也不是,您使用 Promise.all
的方式很奇怪 - 您总是提供一个空数组。 Promise.all
期望作为输入的承诺数组,它等待输入中的所有承诺得到解决或其中任何一个失败。
它 returns 一个要么被解决(如果所有输入的承诺都正确)要么被拒绝(如果任何一个失败)的承诺。在你原来的情况下 Promise.all
总是被解决,因为输入列表是空的
- 我的文件是真的在所有请求完成后写入,还是在它们完成时写入?
方法writeOutput
在从makeBatchRequests
返回的Promise被解析后被调用,它是用两个参数调用的-fileName
,这是 undefined
因为它从未在您的代码中定义,第二个是 result
- 这是一个 Array
其成员是 promisesArray
的解析结果,它始终为空.所以从技术上讲,是的,该函数在所有请求完成后被调用,但是没有数据被写入文件(哦,实际上,空字符串""
是[].toString()
将打印到文件 :] )
- 我承诺写功能好吗?
是,你做对了。
除此之外,尝试重写您的代码,一步一步,在进行每一步时对其进行测试,并将预期结果与实际结果进行比较。 正如上面的答案中提到的,有很多东西需要修复,祝你好运! :]
那么,我认为问题可能出在 writeOutput(fileName, result)
,你确定 returns 是一个承诺吗?
这更像是一个建议,而不是实际答案,但请尝试这样做:
scrapy.getStanceMods()
.then(['www.google.com', 'www.reddit.com'])
.then(makeBatchRequest)
.then(result => {
return writeOutput(fileName, result))
.then(console.log("Completed."))
.catch(error=>console.log('will catch inner errors'))
})
.catch(error =>console.error(error));