如何在 NodeJS (Bluebird) 中通过 promise 链持久化数据
How to persist data through promise chain in NodeJS (Bluebird)
跟进 (发布的答案有效,但立即揭示了一个新问题)
这是我第一次在 NodeJS 中使用 promises,所以如果一些约定没有得到很好的遵守或代码草率,我深表歉意。我正在尝试聚合来自多个 API 的数据,将其放入数据库,然后根据数据的异同计算一些统计数据。作为起点,我试图为 API 中的一个获得一个 API 令牌。
这是我的完整代码:
var Promise = require('bluebird');
var fs = require('fs');
var request = require('request');
Promise.promisifyAll(fs);
Promise.promisifyAll(request);
// tilde-expansion doesn't follow the callback(err, data) convention
var tilde = function(str) {
var _tilde = require('tilde-expansion');
return new Promise(function(resolve, reject) {
try {
_tilde(str, resolve);
} catch(e) {
reject(e);
}
});
}
var getToken = function() {
return request.getAsync(process.env.token_url, {
headers: {
"Content-Type": "applications/x-www-form-urlencoded"
},
form: {
client_id: process.env.client_id,
client_secret: process.env.client_secret,
grant_type: "client_credentials"
}
})
.then(function(resp) { return resp.body; });
}
var tokenFile = tilde(process.env.token_file)
.catch(function(err) {
console.log("Error parsing path to file... can not recover");
});
var token = tokenFile
.then(fs.readFileAsync) //, "utf8")
.then(function(data) {
console.log("Token (from file): " + data);
return data;
})
.then(JSON.parse)
.catch(function(err) {
console.log("Error reading token from file... getting a new one");
return getToken()
.then(function(data) {
console.log("Token (from API): " + data);
return data;
})
.then(JSON.stringify)
.then(fs.writeFileAsync.bind(null, tokenFile.value()));
});
token.then(function(data) {
console.log("Token (from anywhere): " + token.value);
});
当前正在记录此代码:
Token: undefined
如果我退回到API。假设我正确地做了我的承诺(.catch()
可以 return 承诺,对吧?)那么我会假设问题正在发生,因为 fs.writeFileAsync
return 无效。
我想在此承诺的末尾附加一个 .return()
,但我如何才能访问 getToken()
的 return 值?我尝试了以下方法:
.catch(function(err) {
console.log("Error reading token from file... getting a new one");
var token = "nope";
return getToken()
.then(function(data) {
console.log("Token (from API): " + data);
token = data;
return data;
})
.then(JSON.stringify)
.then(fs.writeFileAsync.bind(null, tokenFile.value()))
.return(token);
});
但是这会记录 "nope"。
整个周末,我继续研究 promises,在做出关键性的认识后,我能够开发出解决方案。在这里发布实现和解决方案:
实现
Promises 的发明使得异步代码可以以同步方式使用。考虑以下因素:
var data = processData(JSON.parse(readFile(getFileName())));
这相当于:
var filename = getFileName();
var fileData = readFile(filename);
var parsedData = JSON.parse(fileData);
var data = processData(parsedData);
如果这些函数中的任何一个是异步的,那么它就会中断,因为值没有按时准备好。所以对于那些我们曾经使用回调的异步位:
var filename = getFileName();
var data = null;
readFile(filename, function(fileData){
data = processData(JSON.parse(fileData));
});
这不仅丑陋,而且破坏了很多东西,例如堆栈跟踪、try/catch 块等
Promise 模式 解决了这个问题,让你说:
var filename = getFileName();
var fileData = filename.then(readFile);
var parsedData = fileData.then(JSON.parse);
var data = parsedData.then(processData);
无论这些函数是同步的还是异步的,此代码都有效,并且回调为零。它实际上都是 synchronous 代码,但我们不是传递 values,而是传递 promises。
这让我意识到:对于可以用 promise 编写的每一段代码,都有一个同步推论
解决方案
意识到这一点,如果所有函数都是同步的,我会尝试考虑我的代码:
try {
var tokenFile = tilde(process.env.token_file)
} catch(err) {
throw new Error("Error parsing path to file... can not recover");
}
var token = null;
try {
token = JSON.parse(readFile(tokenFile));
} catch(err) {
token = getToken();
writeFile(tokenFile, JSON.stringify(token));
}
console.log("Token: " + token.value);
这样构造后,promise版本顺理成章:
var tokenFile = tilde(process.env.token_file)
.catch(function(err) {
throw new Error("Error parsing path to file... can not recover");
});
var token = tokenFile
.then(readFile)
.then(JSON.parse)
.catch(function(err) {
var _token = getToken();
_token
.then(JSON.stringify)
.then(writeFile.bind(null, tokenFile.value));
return _token;
});
跟进
这是我第一次在 NodeJS 中使用 promises,所以如果一些约定没有得到很好的遵守或代码草率,我深表歉意。我正在尝试聚合来自多个 API 的数据,将其放入数据库,然后根据数据的异同计算一些统计数据。作为起点,我试图为 API 中的一个获得一个 API 令牌。
这是我的完整代码:
var Promise = require('bluebird');
var fs = require('fs');
var request = require('request');
Promise.promisifyAll(fs);
Promise.promisifyAll(request);
// tilde-expansion doesn't follow the callback(err, data) convention
var tilde = function(str) {
var _tilde = require('tilde-expansion');
return new Promise(function(resolve, reject) {
try {
_tilde(str, resolve);
} catch(e) {
reject(e);
}
});
}
var getToken = function() {
return request.getAsync(process.env.token_url, {
headers: {
"Content-Type": "applications/x-www-form-urlencoded"
},
form: {
client_id: process.env.client_id,
client_secret: process.env.client_secret,
grant_type: "client_credentials"
}
})
.then(function(resp) { return resp.body; });
}
var tokenFile = tilde(process.env.token_file)
.catch(function(err) {
console.log("Error parsing path to file... can not recover");
});
var token = tokenFile
.then(fs.readFileAsync) //, "utf8")
.then(function(data) {
console.log("Token (from file): " + data);
return data;
})
.then(JSON.parse)
.catch(function(err) {
console.log("Error reading token from file... getting a new one");
return getToken()
.then(function(data) {
console.log("Token (from API): " + data);
return data;
})
.then(JSON.stringify)
.then(fs.writeFileAsync.bind(null, tokenFile.value()));
});
token.then(function(data) {
console.log("Token (from anywhere): " + token.value);
});
当前正在记录此代码:
Token: undefined
如果我退回到API。假设我正确地做了我的承诺(.catch()
可以 return 承诺,对吧?)那么我会假设问题正在发生,因为 fs.writeFileAsync
return 无效。
我想在此承诺的末尾附加一个 .return()
,但我如何才能访问 getToken()
的 return 值?我尝试了以下方法:
.catch(function(err) {
console.log("Error reading token from file... getting a new one");
var token = "nope";
return getToken()
.then(function(data) {
console.log("Token (from API): " + data);
token = data;
return data;
})
.then(JSON.stringify)
.then(fs.writeFileAsync.bind(null, tokenFile.value()))
.return(token);
});
但是这会记录 "nope"。
整个周末,我继续研究 promises,在做出关键性的认识后,我能够开发出解决方案。在这里发布实现和解决方案:
实现
Promises 的发明使得异步代码可以以同步方式使用。考虑以下因素:
var data = processData(JSON.parse(readFile(getFileName())));
这相当于:
var filename = getFileName();
var fileData = readFile(filename);
var parsedData = JSON.parse(fileData);
var data = processData(parsedData);
如果这些函数中的任何一个是异步的,那么它就会中断,因为值没有按时准备好。所以对于那些我们曾经使用回调的异步位:
var filename = getFileName();
var data = null;
readFile(filename, function(fileData){
data = processData(JSON.parse(fileData));
});
这不仅丑陋,而且破坏了很多东西,例如堆栈跟踪、try/catch 块等
Promise 模式 解决了这个问题,让你说:
var filename = getFileName();
var fileData = filename.then(readFile);
var parsedData = fileData.then(JSON.parse);
var data = parsedData.then(processData);
无论这些函数是同步的还是异步的,此代码都有效,并且回调为零。它实际上都是 synchronous 代码,但我们不是传递 values,而是传递 promises。
这让我意识到:对于可以用 promise 编写的每一段代码,都有一个同步推论
解决方案
意识到这一点,如果所有函数都是同步的,我会尝试考虑我的代码:
try {
var tokenFile = tilde(process.env.token_file)
} catch(err) {
throw new Error("Error parsing path to file... can not recover");
}
var token = null;
try {
token = JSON.parse(readFile(tokenFile));
} catch(err) {
token = getToken();
writeFile(tokenFile, JSON.stringify(token));
}
console.log("Token: " + token.value);
这样构造后,promise版本顺理成章:
var tokenFile = tilde(process.env.token_file)
.catch(function(err) {
throw new Error("Error parsing path to file... can not recover");
});
var token = tokenFile
.then(readFile)
.then(JSON.parse)
.catch(function(err) {
var _token = getToken();
_token
.then(JSON.stringify)
.then(writeFile.bind(null, tokenFile.value));
return _token;
});