【问题标题】:How to persist data through promise chain in NodeJS (Bluebird)如何在 NodeJS (Bluebird) 中通过 Promise 链持久化数据
【发布时间】:2016-09-26 01:59:31
【问题描述】:

跟进Swap order of arguments to "then" with Bluebird / NodeJS Promises(发布的答案有效,但立即发现了一个新问题)

这是我第一次在 NodeJS 中使用 Promise,所以如果某些约定没有得到很好的遵守或代码草率,我深表歉意。我正在尝试聚合来自多个 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() 可以返回一个承诺,对吗?)然后我会假设问题正在发生,因为fs.writeFileAsync 返回 void。

我想在此承诺的末尾附加一个.return(),但我如何才能访问getToken() 的返回值?我尝试了以下方法:

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

但是这会记录“不”。

【问题讨论】:

  • 什么是.return()
  • 这是一种bluebird便捷方法,.then(function(value) { return value; });的缩写
  • 你不应该承诺request,而应该使用request-promise。它使用 Bluebird Promise 构建
  • @peteb 虽然我喜欢一个已经为我完成我想要完成的工作的库的想法,但如果更新了request,那么我需要等待多长时间才能更新到传播到request-promise?我对长依赖链非常警惕 - 我宁愿知道我始终拥有最新和最好的。

标签: javascript node.js promise bluebird


【解决方案1】:

在周末,我继续研究 Promise,并在做出关键性认识后,开发出解决方案。在这里发布实现和解决方案:

实现

发明了 Promise,以便可以以同步方式使用异步代码。考虑以下几点:

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

无论这些函数是同步的还是异步的,这段代码都能正常工作,并且回调为零。这实际上都是 同步 代码,但是我们不是传递 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;
    });

【讨论】:

    猜你喜欢
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    相关资源
    最近更新 更多