简体   繁体   English

如何通过NodeJS中的Promise链持久化数据(Bluebird)

[英]How to persist data through promise chain in NodeJS (Bluebird)

Follow-up to Swap order of arguments to "then" with Bluebird / NodeJS Promises (the posted answer worked, but immediately revealed a new issue) Bluebird / NodeJS Promises的参数交换为“ then”的后续操作(发布的答案有效,但立即发现了一个新问题)

This is the first time I've ever used promises in NodeJS so I apologize if some conventions are poorly adhered to or the code is sloppy. 这是我第一次在NodeJS中使用Promise,因此对于某些约定未得到严格遵守或代码草率的行为,我深表歉意。 I'm trying to aggregate data from multiple APIs, put it in a database, then compute some statistics based on similarities and differences in the data. 我正在尝试聚合来自多个API的数据,将其放入数据库中,然后根据数据的异同来计算一些统计信息。 As a starting point I'm trying to get an API token for a single one of the APIs. 首先,我尝试获取单个API的API令牌。

Here is my full code: 这是我的完整代码:

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);
});

This code is currently logging: 该代码当前正在记录:

Token: undefined

if I fall back to the API. 如果我退回到API。 Assuming I did my promise stuff correctly ( .catch() can return a promise, right?) then I would assume the issue is occurring because fs.writeFileAsync returns void. 假设我正确完成了我的诺言内容( .catch()可以返回一个诺言,对吗?),那么我会认为问题正在发生,因为fs.writeFileAsync返回void。

I would like to append a .return() on the end of this promise, but how would I gain access to the return value of getToken() ? 我想追加一个.return()这一承诺的结束,但我将如何获得对返回值的访问getToken() I tried the following: 我尝试了以下方法:

    .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);
    });

However this logs "nope". 但是,这记录为“不”。

Over the weekend I continued my research on promises and upon making a pivotal realization I was able to develop the solution to this. 在周末,我继续了对诺言的研究,并且在实现关键性实现后,我得以开发出解决方案。 Posting here both the realization and the solution: 在此同时发布实现和解决方案:

The Realization 实现

Promises were invented so that asynchronous code could be used in a synchronous manner. 发明了承诺,以便可以以同步方式使用异步代码。 Consider the following: 考虑以下:

var data = processData(JSON.parse(readFile(getFileName())));

This is the equivalent of: 这等效于:

var filename = getFileName();
var fileData = readFile(filename);
var parsedData = JSON.parse(fileData);
var data = processData(parsedData);

If any one of these functions is asynchronous then it breaks, because the value isn't ready on time. 如果这些函数中的任何一个是异步的,那么它将中断,因为该值未按时准备好。 So for those asynchronous bits we used to use callbacks: 因此,对于那些异步位,我们曾经使用回调:

var filename = getFileName();
var data = null;
readFile(filename, function(fileData){
    data = processData(JSON.parse(fileData));
});

This is not only ugly, but breaks a lot of things like stack traces, try/catch blocks, etc. 这不仅丑陋,而且破坏了很多东西,例如堆栈跟踪,try / catch块等。

The Promise pattern fixed this, letting you say: Promise模式解决了这个问题,让您说:

var filename = getFileName();
var fileData = filename.then(readFile);
var parsedData = fileData.then(JSON.parse);
var data = parsedData.then(processData);

This code works regardless of whether these functions are synchronous or asynchronous, and there are zero callbacks. 不管这些函数是同步的还是异步的,此代码都有效,并且回调为零。 It's actually all synchronous code, but instead of passing values around, we pass promises around. 它实际上是所有同步代码,但是我们传递承诺而不是传递

The led me to the realization that: for every bit of code that can be written with promises, there is a synchronous corollary 使我意识到: 对于可以用promise编写的每一段代码,都有一个同步的推论。

The solution 解决方案

Realizing this, I tried to consider my code if all of the functions were synchronous: 意识到这一点,我尝试考虑所有功能是否都是同步的代码:

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);

After framing it like this, the promise version follows logically: 在像这样进行构架之后,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;
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM