Continuable if error is null
That is basically what promises, and monads in the general sense, do. If you take the abstraction one step forward, you can generalize the idea of a continuation into a monad interface (using the FantasyLand spec):

function Cont(run) {
  this.run = run
}

Cont.of = function(a) {
  return new Cont(function(next) {
    next(a)
  })
}

Cont.error = function(msg) {
  return new Cont(function(_, error) {
    error(msg)
  })
}

Cont.prototype.chain = function(f) {
  return new Cont(function(next, error) {
    return this.run(function(a) {
      return f(a).run(next, error)
    }, error)
  }.bind(this))
}


Now your functions would have to return objects in that monad:

var msg = 'hello'
var msgErr = 'some error'

function f1(a) {
  console.log('f1', a === msg)
  return Cont.of(a)
}

function f2(a) {
  console.log('f2', a === msg)
  return Cont.error(msgErr)
}

// won't execute
function dummy() {
  console.log('dummy')
}


Then you can chain the continuations, and run the final computation, providing a callback for the success case, and an optional callback for the error case:

var chain = f1(msg).chain(f2).chain(dummy)

// chain.run(success, error)
chain.run(console.log, console.log)
// f1, true
// f2, true
// some error


Once you have this in place you can abstract regular callback-based functions to use the monad:

var cc = function(f) {
  return function() {
    var args = Array.prototype.slice.call(arguments)
    var cb = f.bind.apply(f, [null].concat(args))
    return new Cont(function(next, error) {
      cb(function(err, value) {
        if (err) return error(err)
        next(value)
      })
    })
  }
}

function f1(a, cb) {
  console.log('f1', a === msg)
  cb(null, a)
}

function f2(a, cb) {
  console.log('f2', a === msg)
  cb(msgErr)
}

var chain = cc(f1)(msg).chain(cc(f2)).chain(cc(dummy))

chain.run(console.log, console.log)
// f1, true
// f2, true
// some error


Of course you could apply cc as a decorator, instead of inline:

var f1 = cc(function(a, cb) {
  console.log('f1', a === msg)
  cb(null, a)
})

var f2 = cc(function(a, cb) {
  console.log('f2', a === msg)
  cb(msgError)
})