title: Why aren’t these Bluebird promise chains equivalent?
body: <p>I’m introducing promises using the Bluebird library to my Javascript code, as they seem to be the closest available thing to the flow control combinators I’m used to in Haskell. The following Gulp task works for me: </p>
  
  <pre><code>gulp.task('upload', function(callback) {
    configAWSFromFile();
    var functionName = 'redacted',
        Lambda = new AWS.Lambda();
    Promise.promisifyAll(Object.getPrototypeOf(Lambda));
  
    function uploadLambdaFn(lambdaFn, fileStream) {
      var params = {
        FunctionName: functionName,
        Handler: lambdaFn.Configuration.Handler,
        // snip
        FunctionZip: fileStream
      };
      return Lambda.uploadFunctionAsync(params);
    }
  
    return Promise.join(Lambda.getFunctionAsync({FunctionName: functionName}),
                        fs.readFileAsync(path.join(destPrefix, uploadPackage)),
                        uploadLambdaFn)
      .then(function(response) {
        gutil.log('Response:\n' + util.inspect(response));
      });
  });
  </code></pre>
  
  <p>However, when I try to refactor the upload step out of the config object creation function, it breaks down: </p>
  
  <pre><code>gulp.task('upload', function(callback) {
    configAWSFromFile();
    var functionName = 'redacted',
        Lambda = new AWS.Lambda();
    Promise.promisifyAll(Object.getPrototypeOf(Lambda));
  
    // rename function
    function mkLambdaFnConfig(lambdaFn, fileStream) {
      var params = {
        FunctionName: functionName,
        Handler: lambdaFn.Configuration.Handler,
        // snip
        FunctionZip: fileStream
      };
      return params;  // return immediate value
    }
  
    return Promise.join(Lambda.getFunctionAsync({FunctionName: functionName}),
                        fs.readFileAsync(path.join(destPrefix, uploadPackage)),
                        Promise.method(mkLambdaFnConfig))  // wrap regular function
      .then(Lambda.uploadFunctionAsync)  // add the upload to the chain
      .then(function(response) {
        gutil.log('Response:\n' + util.inspect(response));
      });
  });
  </code></pre>
  
  <p>Gives the following stack trace (paths have been edited to be relative): </p>
  
  <pre><code>TypeError: undefined is not a function
      at svc.(anonymous function) (./node_modules/aws-sdk/lib/service.js:399:21)
      at tryCatcher (./node_modules/bluebird/js/main/util.js:24:31)
      at ret (eval at &lt;anonymous&gt; (./node_modules/bluebird/js/main/promisify.js:154:12), &lt;anonymous&gt;:13:39)
      at tryCatcher (./node_modules/bluebird/js/main/util.js:24:31)
      at Promise._settlePromiseFromHandler (./node_modules/bluebird/js/main/promise.js:466:31)
      at Promise._settlePromiseAt (./node_modules/bluebird/js/main/promise.js:545:18)
      at Promise._settlePromises (./node_modules/bluebird/js/main/promise.js:661:14)
      at Async._drainQueue (./node_modules/bluebird/js/main/async.js:79:16)
      at Async._drainQueues (./node_modules/bluebird/js/main/async.js:89:10)
      at Immediate.Async.drainQueues [as _onImmediate] (./node_modules/bluebird/js/main/async.js:14:14)
      at processImmediate [as _immediateCallback] (timers.js:358:17)
  </code></pre>
  
  <p>I get an identical stack trace if I change the <code>mkLambdaFnConfig</code> function to return <code>Promise.resolve(params)</code> instead of wrapping <code>mkLambdaFnConfig</code> in <code>Promise.method</code>: </p>
  
  <pre><code>gulp.task('upload', function(callback) {
    configAWSFromFile();
    var functionName = 'redacted',
        Lambda = new AWS.Lambda();
    Promise.promisifyAll(Object.getPrototypeOf(Lambda));
  
    // rename function
    function mkLambdaFnConfig(lambdaFn, fileStream) {
      var params = {
        FunctionName: functionName,
        Handler: lambdaFn.Configuration.Handler,
        // snip
        FunctionZip: fileStream
      };
      return Promise.resolve(params);  // return already-fulfilled promise
    }
  
    return Promise.join(Lambda.getFunctionAsync({FunctionName: functionName}),
                        fs.readFileAsync(path.join(destPrefix, uploadPackage)),
                        mkLambdaFnConfig)  // no additional wrapping
      .then(Lambda.uploadFunctionAsync)  // add the upload to the chain
      .then(function(response) {
        gutil.log('Response:\n' + util.inspect(response));
      });
  });
  </code></pre>
  
  <p>Generates the stack trace (again, with relative paths): </p>
  
  <pre><code>TypeError: undefined is not a function
      at svc.(anonymous function) (./node_modules/aws-sdk/lib/service.js:399:21)
      at tryCatcher (./node_modules/bluebird/js/main/util.js:24:31)
      at ret (eval at &lt;anonymous&gt; (./node_modules/bluebird/js/main/promisify.js:154:12), &lt;anonymous&gt;:13:39)
      at tryCatcher (./node_modules/bluebird/js/main/util.js:24:31)
      at Promise._settlePromiseFromHandler (./node_modules/bluebird/js/main/promise.js:466:31)
      at Promise._settlePromiseAt (./node_modules/bluebird/js/main/promise.js:545:18)
      at Promise._settlePromises (./node_modules/bluebird/js/main/promise.js:661:14)
      at Async._drainQueue (./node_modules/bluebird/js/main/async.js:79:16)
      at Async._drainQueues (./node_modules/bluebird/js/main/async.js:89:10)
      at Immediate.Async.drainQueues [as _onImmediate] (./node_modules/bluebird/js/main/async.js:14:14)
      at processImmediate [as _immediateCallback] (timers.js:358:17)
  </code></pre>
  
  <p>I suspect that I’m missing some basic component of how promises work. I had thought that <code>Promise.resolve</code> and <code>Promise.method</code> were lifting functions like monadic <code>return</code> and applicative <code>pure</code>, but I’m guessing now that’s a gross misunderstanding. </p>
  
  <h2>Edit for future visitors:</h2>
  
  <p>This is the working code I ended up with (after @Bergi pointed out that it’s just a binding issue): </p>
  
  <pre><code>gulp.task('upload', function(callback) {
    configAWSFromFile();
    var functionName = 'redacted',
        Lambda = new AWS.Lambda();
    // As noted by @Esailija, this should be moved to init.
    Promise.promisifyAll(Object.getPrototypeOf(Lambda));
  
    function mkLambdaFnConfig(lambdaFn, fileStream) {
      var params = {
        FunctionName: functionName,
        Handler: lambdaFn.Configuration.Handler,
        // snip
        FunctionZip: fileStream
      };
      return params;
    }
  
    return Promise.join(Lambda.getFunctionAsync({FunctionName: functionName}),
                        fs.readFileAsync(path.join(destPrefix, uploadPackage)),
                        Promise.method(mkLambdaFnConfig))  // wrap synchronous function
      // Methods added as callbacks need to be bound, just like usual!
      .then(Lambda.uploadFunctionAsync.bind(Lambda))
      .then(function(response) {
        gutil.log('Response:\n' + util.inspect(response));
      });
  });
  </code></pre>