Разработих малка библиотека за Dynamics CRM REST/ODATA уеб услуга (CrmRestKit). Библиотеката зависи от jQuery и използва модела на обещанието, респективно подобен на обещанието модел на jQuery.
Сега ми харесва да пренеса тази библиотека към bluebird и да премахна зависимостта от jQuery. Но се сблъсквам с проблем, защото bluebird не поддържа синхронното разрешаване на обекти на обещания.
Малко контекстна информация:
API на CrmRestKit изключва незадължителен параметър, който определя дали извикването на уеб услугата трябва да се извърши в синхронизиран или асинхронен режим:
CrmRestKit.Create( 'Account', { Name: "foobar" }, false ).then( function ( data ) {
....
} );
Когато подадете "true" или пропуснете последния параметър, методът ще създаде записа в синхрон. режим.
Понякога е необходимо да се извърши операция в режим на синхронизиране, например можете да напишете JavaScript код за Dynamics CRM, който е включен за събитието за запазване на формуляр и в този манипулатор на събития трябва да извършите операция за синхронизиране за валидиране ( например потвърдете, че съществува определен брой дъщерни записи, в случай че съществува правилният брой записи, отменете операцията за запазване и покажете съобщение за грешка).
Проблемът ми сега е следният: bluebird не поддържа разделителната способност в синхронен режим. Например, когато направя следното, манипулаторът "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
Бих очаквал, че "вторият" се появява след "първия", защото обещанието вече е разрешено със стойност. Така че бих предположил, че тогавашният манипулатор на събития се извиква незабавно когато се приложи върху вече разрешен обект на обещание.
Когато направя същото (използвам след това върху вече разрешено обещание) с 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
Има ли начин bluebird да работи по същия начин?
Актуализация: Предоставеният код беше само за да илюстрира проблема. Идеята на lib е: независимо от режима на изпълнение (sync, async), извикващият винаги ще работи с обещаващ обект.
Относно „... питането на потребителя... изглежда няма смисъл“: Когато предоставите два метода „CreateAsync“ и „CreateSync“, потребителят също трябва да реши как да се изпълни операцията.
Във всеки случай с текущата реализация поведението по подразбиране (последният параметър е незадължителен) е асинхронно изпълнение. Така че 99% от кода изисква обещаващ обект, незадължителният параметър се използва само за 1% от случаите, когато просто се нуждаете от синхронизиране. Освен това разработих lib за себе си и използвам в 99,9999% от случаите асинхронен режим, но реших, че е хубаво да имаш опцията да вървиш по пътя на синхронизирането, както желаеш.
Но мисля, че разбрах смисъла, че методът за синхронизиране трябва просто да върне стойността. За следващото издание (3.0) ще внедря "CreateSync" и "CreateAsync".
Благодаря за вашето мнение.
Актуализация-2 Моето намерение за незадължителния параметър беше да осигуря последователно поведение И да предотвратя логическа грешка. Да приемем, че сте потребител на моя метод "GetCurrentUserRoles", който използва lib. Така че методът винаги ще връща обещание, което означава, че трябва да използвате метода "then", за да изпълните код, който зависи от резултата. Така че, когато някой пише код като този, съгласен съм, че е напълно погрешен:
var currentUserRoels = null;
GetCurrentUserRoles().then(function(roles){
currentUserRoels = roles;
});
if( currentUserRoels.indexOf('foobar') === -1 ){
// ...
}
Съгласен съм, че този код ще се счупи, когато методът „GetCurrentUserRoles“ се промени от sync на async.
Но разбирам, че това не е добър дизайн, защото потребителят би трябвало сега, когато се занимава с асинхронен метод.
CrmRestKit.CreateAsync
иCrmRestKit.CreateSync
вместоCrmRestKit.Create({async: ?})
. Това е напълно различно от функция, която понякога може да знае своята върната стойност синхронно (напр. кеш от първо ниво за извикване на база данни) - person Esailija   schedule 16.01.2014CrmRestKit.Create(..., sync)
) няма смисъл? Ако е така, съгласен съм. - person Denys Séguret   schedule 16.01.2014CreateSync()
няма смисъл да връща обещание, тъй като това е нормално синхронно извикване. Същото претоварване на параметър като OP се използва вXMLHttpRequest
, което може да бъде заменено сopenAsync()
иopenSync()
, но вашият оригинален коментар бърка това с метод, който понякога се връща синхронно. Това не е същото, защото претоварването при async = false винаги се връща синхронно, така че в този случай няма нужда от обещание. - person Esailija   schedule 16.01.2014.responseText
директно. - person Esailija   schedule 16.01.2014