现在我喜欢将此lib移植到bluebird并删除jQuery依赖关系.但是我面临一个问题,因为蓝鸟不支持承诺对象的同步解决.
一些上下文信息:
CrmRestKit的API除了一个可选参数,可以定义是否应该以同步或异步模式执行Web服务调用:
CrmRestKit.Create( 'Account',{ Name: "foobar" },false ).then( function ( data ) { .... } );
当您传递“true”或省略最后一个参数时,方法将同步创建记录.模式.
有时,需要以同步模式执行操作,例如您可以编写用于表单保存事件的Dynamics CRM的JavaScript代码,并在此事件处理程序中执行同步操作进行验证(例如验证存在一定数量的子记录,如果存在正确的记录数,则取消保存操作并显示错误消息).
我现在的问题是:蓝鸟不支持同步模式下的分辨率.例如,当我执行以下操作时,“then”处理程序以异步方式调用:
function print( text ){ console.log( 'print -> %s',text ); return text; } /// /// 'Promise.cast' cast the given value to a trusted promise. /// function getSomeTextSimpleCast( opt_text ){ var text = opt_text || 'Some fancy text-value'; return Promise.cast( text ); } getSomeTextSimpleCast('first').then(print); print('second');
输出如下:
print -> second print -> first
我希望“第二”出现在“第一”之后,因为承诺已经用一个价值解决了.所以我假设当应用在已经解决的promise对象上时,立即调用一个事件处理程序.
当我做同样的(使用然后在已经解决的承诺)与jQuery我将有我的预期结果:
function jQueryResolved( opt_text ){ var text = opt_text || 'jQuery-Test Value',dfd = new $.Deferred(); dfd.resolve(text); // return an already resolved promise return dfd.promise(); } jQueryResolved('third').then(print); print('fourth');
这将产生以下输出:
print -> third print -> fourth
有没有办法让蓝鸟以同样的方式工作?
更新:
提供的代码只是为了说明问题. lib的想法是:不管执行模式(sync,async),调用者将始终处理promise对象.
关于“…请求用户…似乎没有任何意义”:当您提供两种方法“CreateAsync”和“CreateSync”时,用户还可以决定如何执行操作.
无论如何,当前实现的默认行为(最后一个参数是可选的)是一个异步执行.所以99%的代码需要一个promise对象,可选参数只适用于您只需要同步执行的1%情况.此外,我开发自己的lib,我使用99,9999%的异步模式,但我认为很高兴有选择去同步路,你喜欢.
但是我认为我有一个同步方法应该简单地返回值.对于下一个版本(3.0),我将实现“CreateSync”和“CreateAsync”.
感谢您的输入.
更新2
我的可选参数的意图是确保一致性行为,并防止逻辑错误.假设你是我使用lib的方法“GetCurrentUserRoles”的消费者.所以方法将永远返回承诺,这意味着你必须使用“then”方法来执行取决于结果的代码.所以当有些人写这样的代码时,我同意这是完全错误的:
var currentUserRoels = null; GetCurrentUserRoles().then(function(roles){ currentUserRoels = roles; }); if( currentUserRoels.indexOf('foobar') === -1 ){ // ... }
我同意,当方法“GetCurrentUserRoles”从同步更改为异步时,此代码将中断.
但是我明白这不是一个好的设计,因为消费者现在应该使用异步方法.
解决方法
我认为正在提出的根本问题是,如果承诺已经完成,完成的承诺是否应该立即运行回调.我可以想到这可能会发生的很多原因 – 例如,一个异步保存过程,只有在进行了更改时才能保存数据.它可能能够以同步方式检测来自客户端的变化,而不必经历外部资源,但是如果检测到改变,则仅需要异步操作.
在具有异步调用的其他环境中,该模式似乎是开发人员负责了解他们的工作可能会立即完成(例如,.NET框架的异步模式的实现可以适应这一点).这不是框架的设计问题,它的实现方式.
JavaScript的开发人员(和上面的许多评论者)似乎对此有不同的观点,坚持认为如果某些内容可能是异步的,则它必须始终是异步的.这是否是“正确的”是不重要的 – 根据我在https://promisesaplus.com/发现的规范,项目2.2.4规定,基本上没有回调可以调用,直到你被称为“脚本代码”或“用户代码“;也就是说,规范清楚地表明,即使承诺完成,您也不能立即调用回调.我已经检查了其他几个地方,他们对这个话题一无所知,或者同意原来的来源.我不知道https://promisesaplus.com/是否可以被认为是这方面的一个明确的信息来源,但是我看不到其他来源不同意它似乎是最完整的.
这个限制是有点任意的,我坦白地说喜欢.NET的这个角度.我会把它留给别人来决定他们是否认为“不好的代码”来做某些可能或者可能不是同步的东西,看起来是异步的.
您的实际问题是Bluebird是否可以配置为执行非JavaScript行为.在性能方面,这样做可能会有一点小小的好处,而在JavaScript中,如果您尝试够努力,任何事情都是可能的,但是由于Promise对象在平台上变得越来越普遍,您将会看到将其用作本机组件而不是自定义写入聚合物或图书馆.因此,无论今天的答案如何,在Bluebird中重写承诺可能会在将来导致您出现问题,并且您的代码应该不会被写为依赖于或立即解决承诺.