Importing / exporting only after certain promises

2019-02-13 09:35发布

问题:

Let's say I have a file containing certain promises, that when executed in order, prepares an input file input.txt.

// prepareInput.js

var step1 = function() {
    var promise = new Promise(function(resolve, reject) {
        ...
    });
    return promise;
};
              
var step2 = function() {
    var promise = new Promise(function(resolve, reject) {
        ...
    });
    return promise;
};
              
var step3 = function() {
    var promise = new Promise(function(resolve, reject) {
        ...
    });
    return promise;
};

step1().then(step2).then(step3);

exports.fileName = "input.txt";

If I run node prepareInput.js, the line step1().then(step2).then(step3) gets executed and creates the file.

How can I alter this so that when other files attempt to retrieve fileName from this module, step1().then(step2).then(step3); is run and completed before fileName is exposed? Something along the line of:

// prepareInput.js
...

exports.fileName = 
    step1().then(step2).then(step3).then(function() {
        return "input.txt";
    });


// main.js
var prepareInput = require("./prepareInput");
var inputFileName = require(prepareInput.fileName);
              

Node.js beginner here; apologize beforehand if my approach makes completely no sense... :)

回答1:

You can't directly export the results of something retrieved asynchronously because export is synchronous, so it happens before any async results have been retrieved. The usual solution here is to export a method that returns a promise. The caller can then call that method and use that promise to get the desired async result.

module.exports = function() {
    return step1().then(step2).then(step3).then(function() {
        // based on results of above three operations, 
        // return the filename here
        return ...;
    });
}

The caller then does this:

require('yourmodule')().then(function(filename) {
    // use filename here
});

One thing to keep is mind is that if any operation in a sequence of things is asynchronous, then the whole operation becomes asynchronous and no caller can then fetch the result synchronously. Some people refer to asynchronous as "contagious" in this way. So, if any part of your operation is asynchronous, then you must create an asynchronous interface for the eventual result.


You can also cache the promise so it is only ever run once per app:

module.exports = step1().then(step2).then(step3).then(function() {
    // based on results of above three operations, 
    // return the filename here
    return ...;
});

The caller then does this:

require('yourmodule').then(function(filename) {
    // use filename here
});