我有一个纯粹同步的验证库,但通常用作异步函数链的一部分。但是,我必须维护一个现有的同步API,并希望将promise API作为可选项。我可以以某种方式检测(在运行时)函数是否是Promise链的一部分吗?
使用回调这很容易,因为你可以检查是否传入了一个回调。我知道我可以传递一个可选的promise boolean,但这看起来不太优雅。
我还考虑过做一个回调接口并使用库将回调接口转换为基于promise的接口。但是,我在Haxe工作,我宁愿将变换/抽象降到最低。
我也明白你可以将承诺之间的常规函数夹在中间,但在某些情况下,两者之间的行为会有所不同。
最终修改关于为什么我不能只返回相同的值,第一个例子(下面)似乎没有帮助的许多混乱。请记住,这仍然是简化的。
func getImagesAtInterval(url: NSURL){
let asset : AVURLAsset = AVURLAsset(URL: url, options: nil)
let duration : CMTime = asset.duration
let totalTime = Int(CMTimeGetSeconds(duration) * 1000)
let assetGenerator : AVAssetImageGenerator = AVAssetImageGenerator(asset: asset)
imageSet = [UIImage]()
var value = 0
for var i : Int = 0; i < totalTime; i+=200 {
let time : CMTime = CMTimeMake(Int64(value), 1000)
var imageRef : CGImageRef!
do {
imageRef = try assetGenerator.copyCGImageAtTime(time, actualTime: nil)
} catch let error as NSError {
print("Image generation failed with error \(error)")
}
if let image : UIImage? = UIImage(CGImage: imageRef){
dispatch_async(dispatch_get_main_queue()) {
//I would like to see the images in the previewImageView
//change as the loop operates.
self.previewImageView.image = image
}
imageSet.append(image!)
}
value += 200
}
}
(旧)修改以澄清(但实际上并非如此):
//mix of sync with promise
new Promise(function(resolve, reject){
var safeToAdd = thingTracker.preflight(newThing);
if(safeToAdd){
return client.request.addThing(newThing); //send request to server
} else {
reject(newThing.errorMessages); //requires explicit reject, cannot just pass results along
}
}).then(function(newThing){ //client and server both cool with newThing?
thingTracker.save(newThing);
}).catch(function(errorMessages){ //handles errorMessages from client and server
ui.show(errorMessages);
});
//pure promise
thingTracker.preflight(newThing).then(function(){
return client.request.addThing(newThing); //sends request to server
}).then(function(newThing){ //client and server both cool with newThing?
thingTracker.save(newThing);
}).catch(function(errorMessages){ //handles errorMessages from client and server
ui.show(errorMessages);
});
显然我可以在function preflight(thing){
var validity = thing === 42;
if(promise){
if(validity){
return Promise.resolve(validity);
} else {
return Promise.reject(validity);
}
} else {
return validity;
}
}
的匿名函数中进行相同的检查,但这并不比直接使用同步接口好多少。另请注意,这是一个非常简单的示例,在实际函数中,then
会产生副作用并生成消息。
修改为了更好地说明我的观点,这里的内容是gist。
答案 0 :(得分:6)
可以在promise链中使用同步函数。如果您有一个这样调用的同步API调用:
var info = myApi("foo");
在承诺链中可以很好地使用它:
someAsyncCall().then(myApi).then(someOtherFunction)
您不需要使myApi异步或返回以这种方式使用的承诺。在具有同步函数的promise链中,你唯一不能做的就是它不能是链中的第一个项,但它不需要。由于它是同步的,所以只要有人想要它首先执行,就可以在启动链之前调用它。或者,最糟糕的情况是,你可以这样做:
Promise.resolve().then(myAPI).then(someOtherFunction);
我可以以某种方式检测(在运行时)函数是否是a的一部分 承诺链?
不,你不能(除非你明确地传递了一些告诉它的信息),你不需要为了在诺言链中使用它。您不需要将promise作为.then()
处理程序返回。您只需返回一个值,该值将成为链中该点的promise链值。
我也明白你可以将常规功能夹在中间 承诺,但有些情况下行为会有所不同 两者之间...比如返回假与投掷消息。
我不清楚为什么这种行为必须有所不同。如果返回false
是您正常的同步行为,那么您可以在承诺链中做到这一点 - 链中的下一步只需要处理传递给它的false
值,就像下一行同步代码会做。如果抛出异常是你的正常行为,你也可以在promise链中做到这一点(promise链会将异常变成拒绝),以下代码可以决定它想要处理的方式。如果您的同步函数根据它是否是promise链的一部分而表现不同,那么可以提出一个很好的论据。如果你看到两个不同行为的充分理由,那么你可能应该有两个不同的函数(可以用不同的方式记录)或者传入一个决定行为的选项。
根据您在修改中添加的代码进行评论
您似乎认为通过承诺链调用时,您需要返回已解析或拒绝的承诺链。你不需要这样做。您只需返回一个正常值,promise链将继承您返回的值。除非你想让它成为promise链中的第一个函数,否则没有理由返回已解决或被拒绝的promise,但在这种情况下,它仍然不在promise链中,所以你永远无法检测到它。并且,没有理由将同步操作作为承诺链中的第一个操作。只需先调用同步操作,然后使用异步操作启动您的保证链。
这是一个在promise链中使用的同步函数的演示:
function log(str) {
var div = document.createElement("div");
div.innerHTML = str;
document.body.appendChild(div);
}
// test async call
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}
function square(x) {
return x * x;
}
log("Calculating the square of 9");
delay(500, 9).then(square).then(function(result) {
log("Result = " + result);
});
或者,您甚至可以通过同步操作启动承诺链作为链中的第一个操作:
function log(str) {
var div = document.createElement("div");
div.innerHTML = str;
document.body.appendChild(div);
}
function square(x) {
return x * x;
}
log("Calculating the square of 9");
Promise.resolve(9).then(square).then(function(result) {
log("Result = " + result);
});
答案 1 :(得分:1)
我相信promises只有一个参数,因此无法通过链传递isPromise布尔值,即使你可以,你也必须有意识地添加参数,所以为什么不调用异步功能...
function preflight(thing){
return thing === 42;
}
function preflightAsync(thing){
return new Promise(resolver);
function resolver(resolve,reject){
setTimeout(function foo(){
preflight(thing) ? resolve(true,"this won't make it") : reject();
},1000);
}
}
// Promised
preflightAsync(42).then(doSomethingWithIt).catch(doSomethingWithIt);
preflightAsync(89).then(doSomethingWithIt).catch(doSomethingWithIt);
// Call Directly
doSomethingWithIt(preflight(42));
doSomethingWithIt(preflight(89));
function doSomethingWithIt(result,nada){
result = result ? "BAM!!!" : "WAM!!!";
console.log("doSomethingWithIt",result,nada);//doSomethingWithIt BAM!!! undefined
return result;
}
&#13;
这些示例使用新的本机Promise功能,浏览器支持有限。
答案 2 :(得分:0)
正如我们从之前的答案中看到的那样,你也不能对Promises使用完全相同的功能。在这里添加我的解决方法,遗憾的是扩展了function
原型...
问题在于,如果你想同步使用同一个函数而在Promise中使用arguments
会有所不同。
作为示例 - 截断字符串的函数:
同步:
truncate('A very long string coming from a sync. operation', 10);
异步:
Promise.resolve('A very long string coming from a network request')
.then( truncate(10) )
异步版本会使截断函数认为10
是字符串,您需要在每个函数中检查typeof
或进行欺骗。
什么可行:
Promise.resolve('A very long string coming from a network request')
.then( truncate.it(10) )
如果你之前扩展了函数原型:
Function.prototype.it = (function() {
return function() {
var args = arguments;
return function(){
Array.prototype.push.apply(arguments, args);
return this.apply(null, arguments);
}.bind(this);
};
}());
function foo(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
};
// LOGIC :
foo(1, 2, 3);
// SAME AS
foo.it(2, 3)(1);
// OR
foo.it(3)(1, 2);
// OR pretty useful for .then()
Promise.resolve(1).then(foo.it(2, 3));