.net performance tuning

JB’s dot trace performance profiler is part of its dot ultimate suite(which includes the famous resharper)

the simplest way to use it is to attach to your already running process(the same setting can be reused next time), and check the “collect profiling data from start”, then hit run before the slow performance happens, then take a snapshot as soon as the slowness ends.

then go to the hot spots or just functions list, order by time.

it will give you where the slowness happened, and even system code that ran slow can be dug into who called them.

then you can use https://benchmarkdotnet.org/, a powerful benchmark tool to compare your different versions of implementation.

sample code:

Testing ngrx store’s subscription with appState, action, and selector

之前我研究了一下使用SpyObject来测试NGRX,但这种方法有一个缺点:

You need to mock everything of the spyObject like pipe(), select(), etc. But actually, we may want to test with the real implementation of store, appState, action and selector.

Assuming we have

export const appReducers: ActionReducerMap<AppState, any> = {

    feature1: feature1Reducer,

    feature2: feature2Reducer

};



export class ChangeExpandedState implements Action {

  readonly type = Feature1ActionTypes.CHANGE_EXPANDED_STATE;  // action enum used in reducer,this is old, use https://ngrx.io/api/store/createReducer instead

  constructor(

    public payload: { section: string; subSection?: string; id?: string | null }

  ) {}

}



export function feature1Reducer (state = initialFeature1State, action: Feature1Actions): feature1State {

  switch (action.type) {

    case Feature1ActionTypes. Feature1_LIST_CHANGE:

      return {

        ...state,

        feature1List: action.payload.updatedFeature1List

      };

    ……

    case Feature1ActionTypes. CHANGE_EXPANDED_STATE:

                 const expandBuilder = state.expandState;

   // do something to flipflop based on action.payload.section

  return {

    ...state,

    expandState: expandBuilder

                };

   }

}

In test spec file’s async beforeEach:

TestBed.configureTestingModule({

            imports: [

                StoreModule.forRoot(appReducers),

             …]

         …..

}).compileComponents();

testStore = TestBed.get(Store);

测试用例:

it('should subscribe to someActionState change, () => {

    expect(component.isSomeActionEnabled).toBeFalsy();

    component.isActionSuccess = true; // showing the action response

    testStore.dispatch(new ChangeExpandedState({ section: "someAction" }));

   expect(component.someFeatureEnabled).toBeTruthy();

    expect(component.isActionSuccess).toBeFalsy(); // clear last time response

    testStore.dispatch(new ChangeExpandedState({ section: "someAction" }));

    expect(component.isSomeActionEnabled).toBeFalsy();

});

expression changed after checked


这是一个非常常见的错误,点击到html的78行(实现一个errorHandler去log error.stack的重要性), 可以看到可能出错的几个绑定。最后通过排除法确定是一个属性的绑定(只能通过排除法,这一行html有好几个绑定)

<app-add-account-holder [expandMode]=”clientExpandMode” [isNewHousehold]=”household.isNew” [advisor]=”advisorSelector?.selectedAdvisor” (advisorErrorChange) =”onAdvisorError($event)”></app-add-account-holder>

问题出在ts代码的一个observable的subcription里

        this.showAdvisor = false;
       // this.advisorSelector = null;
代码执行完后,View会进行Change Detection and Binding。于是showAdvisor = false的后果就来了:
由于html里有<div *ngIf=”showAdvisor”
ts代码里的AdvisorSelectorComponent整个就消失了,ViewChild的static:false的作用就是同步更新这种时隐时现,特别是初始时不存在的界面元素的。
  @ViewChild(“advisorSelector”, { static: false })
  advisorSelector?: AdvisorSelectorComponent;
但这个场景下,由于showAdvisor 的变化,属性advisorSelector也就变成了null. 但这个变化是发生在Change Detection and Binding之后的。
Angular本不需要尝试再次绑定[advisorSelector]的。这完全是为了提醒码农你的代码里有属性发生了二次更新,这是危险的因为用户看到的不再是最新的属性绑定结果。但这个出错仅显示在console log,并不会真的crash.