Node.js: 无法 return 来自 array.map() 的新数组
Node.js: Unable to return new array from array.map()
我正在使用一个名为 Okrabyte 的包从文件夹中的每个图像文件中提取单词。结果应该是一个包含提取文本的新数组,我可以在其他函数中使用它。
当我运行这个:
var fs = require("fs");
var okrabyte = require("okrabyte");
fs.readdir("imgs/", function(err, files){
files.map((file)=>{
okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), (err, data)=>{
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
console.log(word);
})
})
})
控制台记录每个单词。为了 return 一个包含这些词的数组,我尝试了以下方法:
async function words() {
await fs.readdir("imgs/", function (err, files) {
return files.map(async (file) => {
await okrabyte.decodeBuffer(fs.readFileSync("imgs/" + file), async (err, data) => {
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
return word
})
})
})
}
var testing = await words();
console.log(testing);
这给了 undefined
我试过将一切变成一个承诺,我试过异步等待,我试过将每个单词推入一个新数组并 returning 该数组正在关闭但没有任何效果 - 我做错了什么??
如果您的映射函数是异步的,那么它是 return 一个承诺,因此您的映射数组实际上是一个承诺数组。但是您可以使用 Promise.all
来获取该数组的解析值。
此外,您正在尝试等待对 fs.readdir
和 okrabyte.decodeBuffer
的调用,它们都接受回调并且 不 return 一个承诺。因此,如果您想在那里使用承诺,则必须手动将它们包装在承诺构造函数中。
我会这样做:
async function words() {
// Wrap `fs` call into a promise, so we can await it:
const files = await new Promise((resolve, reject) => {
fs.readdir("imgs/", (err, files) => { err ? reject(err) : resolve(files); });
});
// Since map function returns a promise, we wrap into a Promise.all:
const mapped = await Promise.all(files.map((file) => {
// Wrap okrabyte.decodeBuffer into promise, and return it:
return new Promise((resolve, reject) => {
okrabyte.decodeBuffer(fs.readFileSync("imgs/" + file), (err, data) => {
if (err) return reject(err);
const splitWords = data.split(" ");
const word = splitWords[0].substr(1);
resolve(word);
})
})
}))
// Mapped is now an array containing each "word".
return mapped;
}
var testing = await words();
// Should now log your array of words correctly.
console.log(testing);
您正在将单词值返回给封闭函数而不是 map() 函数。
希望这段代码对您有所帮助。
async function words() {
global.words = [];
await fs.readdir("imgs/", function(err, files){
return files.map( async(file)=>{
await okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), async (err, data)=>{
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
global.words.push(word);
})
})
})
}
var testing = await words();
testing = global.words;
console.log(testing);
你不应该那样使用 async-await。当你处理承诺时应该使用它。库 okrabyte 使用回调的概念。
我建议您采用这种方法:
(1) 将 okrabyte.decodeBuffer 部分包含在一个函数中,该函数 return 是一个在回调中解析的承诺。
(2) 使用 files.map 生成调用您在 (1)
中定义的函数的承诺数组
(3) 使用Promise.all等待所有的promise执行完成,然后再继续处理所有的词。
演练:
第 1 部分
const processWord = (file) => {
return new Promise((resolve, reject) => {
okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), (err, data)=>{
if (err) {
reject(err); // <--- reject the promise if there was an error
return;
}
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
resolve(word); // <--- resolve the promise with the word
})
});
}
你创建了一个函数,将解码部分包装成一个 promise,最终用这个词解析(或者被错误拒绝)。
第 2 部分
const promises = files.map((file)=>{
return processWord(file);
})
以上将生成一组承诺。
第 3 部分
fs.readdir("imgs/", function(err, files){
const promises = files.map((file)=>{
return processWord(file);
})
Promise.all(promises)
.then(responses => {
// responses holds a list of words
// You will get each word accessing responses[0], responses[1], responses[2], ...
console.log(responses);
})
.catch(error => {
console.log(error); // Deal with the error in some way
});
})
上面使用 Promise.all 假设没有错误发生,在转到 then() 块之前等待所有承诺解决。
您可以在一个方法中进一步隔离上面的构造,该方法将 return 一个包含所有单词列表的承诺,这与第 1 部分中的 processWord 函数中完成的方式大致相同。这样,如果你愿意,你最终可以使用 async-await,而不是在 then() 块中处理事情:
const processEverything = () => {
return new Promise((resolve, reject) => {
fs.readdir("imgs/", function(err, files){
const promises = files.map((file)=>{
return processWord(file);
})
Promise.all(promises)
.then(responses => {
resolve(responses);
})
.catch(error => {
reject(error);
});
})
});
};
const words = await processEverything();
console.log(words);
我正在使用一个名为 Okrabyte 的包从文件夹中的每个图像文件中提取单词。结果应该是一个包含提取文本的新数组,我可以在其他函数中使用它。
当我运行这个:
var fs = require("fs");
var okrabyte = require("okrabyte");
fs.readdir("imgs/", function(err, files){
files.map((file)=>{
okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), (err, data)=>{
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
console.log(word);
})
})
})
控制台记录每个单词。为了 return 一个包含这些词的数组,我尝试了以下方法:
async function words() {
await fs.readdir("imgs/", function (err, files) {
return files.map(async (file) => {
await okrabyte.decodeBuffer(fs.readFileSync("imgs/" + file), async (err, data) => {
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
return word
})
})
})
}
var testing = await words();
console.log(testing);
这给了 undefined
我试过将一切变成一个承诺,我试过异步等待,我试过将每个单词推入一个新数组并 returning 该数组正在关闭但没有任何效果 - 我做错了什么??
如果您的映射函数是异步的,那么它是 return 一个承诺,因此您的映射数组实际上是一个承诺数组。但是您可以使用 Promise.all
来获取该数组的解析值。
此外,您正在尝试等待对 fs.readdir
和 okrabyte.decodeBuffer
的调用,它们都接受回调并且 不 return 一个承诺。因此,如果您想在那里使用承诺,则必须手动将它们包装在承诺构造函数中。
我会这样做:
async function words() {
// Wrap `fs` call into a promise, so we can await it:
const files = await new Promise((resolve, reject) => {
fs.readdir("imgs/", (err, files) => { err ? reject(err) : resolve(files); });
});
// Since map function returns a promise, we wrap into a Promise.all:
const mapped = await Promise.all(files.map((file) => {
// Wrap okrabyte.decodeBuffer into promise, and return it:
return new Promise((resolve, reject) => {
okrabyte.decodeBuffer(fs.readFileSync("imgs/" + file), (err, data) => {
if (err) return reject(err);
const splitWords = data.split(" ");
const word = splitWords[0].substr(1);
resolve(word);
})
})
}))
// Mapped is now an array containing each "word".
return mapped;
}
var testing = await words();
// Should now log your array of words correctly.
console.log(testing);
您正在将单词值返回给封闭函数而不是 map() 函数。
希望这段代码对您有所帮助。
async function words() {
global.words = [];
await fs.readdir("imgs/", function(err, files){
return files.map( async(file)=>{
await okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), async (err, data)=>{
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
global.words.push(word);
})
})
})
}
var testing = await words();
testing = global.words;
console.log(testing);
你不应该那样使用 async-await。当你处理承诺时应该使用它。库 okrabyte 使用回调的概念。
我建议您采用这种方法:
(1) 将 okrabyte.decodeBuffer 部分包含在一个函数中,该函数 return 是一个在回调中解析的承诺。
(2) 使用 files.map 生成调用您在 (1)
中定义的函数的承诺数组(3) 使用Promise.all等待所有的promise执行完成,然后再继续处理所有的词。
演练:
第 1 部分
const processWord = (file) => {
return new Promise((resolve, reject) => {
okrabyte.decodeBuffer(fs.readFileSync("imgs/"+ file), (err, data)=>{
if (err) {
reject(err); // <--- reject the promise if there was an error
return;
}
let splitWords = data.split(" ");
let word = splitWords[0].substr(1);
resolve(word); // <--- resolve the promise with the word
})
});
}
你创建了一个函数,将解码部分包装成一个 promise,最终用这个词解析(或者被错误拒绝)。
第 2 部分
const promises = files.map((file)=>{
return processWord(file);
})
以上将生成一组承诺。
第 3 部分
fs.readdir("imgs/", function(err, files){
const promises = files.map((file)=>{
return processWord(file);
})
Promise.all(promises)
.then(responses => {
// responses holds a list of words
// You will get each word accessing responses[0], responses[1], responses[2], ...
console.log(responses);
})
.catch(error => {
console.log(error); // Deal with the error in some way
});
})
上面使用 Promise.all 假设没有错误发生,在转到 then() 块之前等待所有承诺解决。
您可以在一个方法中进一步隔离上面的构造,该方法将 return 一个包含所有单词列表的承诺,这与第 1 部分中的 processWord 函数中完成的方式大致相同。这样,如果你愿意,你最终可以使用 async-await,而不是在 then() 块中处理事情:
const processEverything = () => {
return new Promise((resolve, reject) => {
fs.readdir("imgs/", function(err, files){
const promises = files.map((file)=>{
return processWord(file);
})
Promise.all(promises)
.then(responses => {
resolve(responses);
})
.catch(error => {
reject(error);
});
})
});
};
const words = await processEverything();
console.log(words);