微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 同步承诺解析(bluebird vs. jQuery)

我为 Dynamics CRM REST/ODATA webservice开发了一个小库(CrmRestKit). lib依赖于jQuery并利用了promise-pattern,这就是jQuery的promise-like-pattern.

现在我喜欢将此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中重写承诺可能会在将来导致您出现问题,并且您的代码应该不会被写为依赖于或立即解决承诺.

原文地址:https://www.jb51.cc/jquery/152285.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐