写下承诺而不打开然后打电话

时间:2015-07-27 01:15:37

标签: javascript function promise lodash bluebird

为了停止编写大量重复的代码,我试图不打开然后调用。我最好只喜欢从顶层传递函数。像这样。

function ensureLink(srcPath, dstPath){
  dstPath = fsRedux.predictDir(srcPath, dstPath)
  var dstDir = path.dirname(dstPath)
  return fsRedux.exists(dstPath)
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link")))
    .then(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir))
    .then(_.bind(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath)))
}

然而,上述代码并不起作用。下面的测试表明您无法通过bound promisifyAll异步功能。原因是then值被传递到这些promises中,导致它们作为调用中的下一个参数,因为这些函数意味着它们作为回调触发,这就是为什么第一个测试错误出现在{ {1}}在摩卡。

Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

存在哪些函数,或者包装绑定函数的方式允许以这种方式处理promise?

更新

我正在寻找一个函数包装器套件库(lodash有一堆),允许partialingbinding from my question earlier或包装函数的简单接口传递给var chai = require("chai") var chaiAsPromised = require("chai-as-promised") chai.use(chaiAsPromised) chai.should() var path = require("path") var _ = require("lodash") var mock = require("mock-fs") var Promise = require("bluebird") var fsRedux = require("./fs-redux") var fsExtra = Promise.promisifyAll(require("fs-extra")) var fs = Promise.promisifyAll(require("fs")) mock({ 'path/hello-alpha.txt': 'file content here', 'path/hello-beta.txt': 'file content here' }) var dstPath = "path/to/fake/dir/" function closedThen(srcPath, dstPath){ dstPath = fsRedux.predictDir(srcPath, dstPath) var dstDir = path.dirname(dstPath) return fsRedux.exists(dstPath) .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) .then(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)) .then(_.bind(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath))) } function openThen(srcPath, dstPath){ dstPath = fsRedux.predictDir(srcPath, dstPath) var dstDir = path.dirname(dstPath) return fsRedux.exists(dstPath) .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) .then(function(){ return _.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)() }) .then(function(){ return _.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath)() }) } describe("issue", function(){ describe("closedThen()", function(){ it("should return then and run promise", function(){ return closedThen("path/hello-alpha.txt", dstPath).then(function(){ return fsExtra.readFileAsync("path/to/fake/dir/hello-alpha.txt", "utf8").should.eventually.equal("file content here") }) }) }) describe("openThen()", function(){ it("should return then and run promise", function(){ return openThen("path/hello-beta.txt", dstPath).then(function(){ return fsExtra.readFileAsync("path/to/fake/dir/hello-beta.txt", "utf8").should.eventually.equal("file content here") }) }) }) }) 或在then内投放。这样链接承诺真的很容易。

理想情况下,我只是想知道如何让线路工作,这是一种包装它的方式,以便当它从那时传递结果时它会忽略它。或推荐的替代方案。

Promise.reduce

2 个答案:

答案 0 :(得分:0)

这里有三个函数,只允许您编写单方法深度承诺。他们使用模块dotty来编辑设置为promise链外的全局范围的对象。

使用wrap,您可以忽略链中的当前值。

function wrap(fn){
  return function(){
    return fn()
  }
}

使用exportResult,您可以存储该值供以后使用。

function exportResult(obj, property){
  return function(value){
    dotty.put(obj, property, value)
    return value
  }
}

使用provideResult,您可以返回之前的结果值,以返回到下一个then来电。

function provideResult(obj, property){
  return function(){
    return dotty.get(obj, property)
  }
}

导致这样的事情。

function ensureLink(srcPath, dstPath){
  dstPath = fsRedux.predictDir(srcPath, dstPath)
  var dstDir = path.dirname(dstPath)
  var values = {}
  return fsRedux.exists(dstPath)
    .then(exportResult(values, "exists"))
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link")))
    .then(wrap(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)))
    .then(wrap(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath)))
    .then(provideResult(values, "exists"))
    // continue the chain provide result from exists...
}

我最初正在寻找更优雅的解决方案。或者就现行标准提出建议。

答案 1 :(得分:0)

以下是使用Ramda的示例。

var Promise = require("bluebird")
var R = require("ramda")
var path = require("path")
var fs = Promise.promisifyAll(require("fs"))
var fse = Promise.promisifyAll(require("fs-extra"))

function ifThrow(value, desiredValue, error){
  if(value == desiredValue) throw error
  return value
}

var fsEnsureLink = function(srcpath, dstpath){
  return R.pipeP.apply(null, [
    R.always(fs.lstatAsync(srcpath).then(R.T, R.F)),
    R.partialRight(ifThrow, false, new Error("source path does not exist")),
    R.always(fs.lstatAsync(dstpath).then(R.T, R.F)),
    R.partialRight(ifThrow, true, new Error("destination path exists")),
    R.always(fse.mkdirsAsync(path.dirname(dstpath))),
    R.always(fs.linkAsync(srcpath, dstpath)),
    R.T,
  ])()
}

fsEnsureLink("./package.json", "./test/package.json")
// promise -> true || Error thrown