programing

Typscript async/ait가 Angular를 업데이트하지 않음JS 뷰

css3 2023. 3. 1. 11:26

Typscript async/ait가 Angular를 업데이트하지 않음JS 뷰

Typescript 2.1(개발자 버전)을 사용하여 비동기/대기 상태를 ES5로 변환하고 있습니다.

비동기 함수로 표시되어야 하는 속성을 변경한 후 뷰가 현재 값으로 업데이트되지 않으므로 매번 $scope를 호출해야 합니다.함수의 끝에 $syslog()가 표시됩니다.

비동기 코드 예시:

async testAsync() {
     await this.$timeout(2000);
     this.text = "Changed";
     //$scope.$apply(); <-- would like to omit this
}

새로운 ★★★★★★★★★★★★★★★★★★★.text값이 이 후 뷰에 표시되지 않습니다.

$scope에 수동으로 전화할 필요가 없는 회피책이 있습니까?매번 $syslog()?

여기의 답은 앵귤러에서 정확합니다.JS는 방법에 대해 모르므로 업데이트된 값에 대해 Angular에 '알려야 합니다.

는 ★★★★★★★★★★★★★★★★★★★★★★★★★★.$q에 대해서, 「」를 사용하는 것이 ,await 방식으로요.앵귤러 웨이'라고 합니다.

비 Angular 메서드는 $q로 쉽게 래핑할 수 있습니다.[모든 Google 지도 함수는 완료 통보를 받기 위해 콜백을 통과하는 패턴을 따르기 때문에 이렇게 포장합니다]

function doAThing()
{
    var defer = $q.defer();
    // Note that this method takes a `parameter` and a callback function
    someMethod(parameter, (someValue) => {
        $q.resolve(someValue)
    });

    return defer.promise;
}

그러면 이렇게 사용할 수 있습니다.

this.doAThing().then(someValue => {
    this.memberValue = someValue;
});

, 하다, 하다, 하다, 하다.await하는 보다 더 방법이 있다$apply 「」, 「」를 사용하는 $digest . 이렇게

async testAsync() {
   await this.$timeout(2000);
   this.text = "Changed";
   $scope.$digest(); <-- This is now much faster :)
}

$scope.$digest 때 더 요. 왜냐하면$scope.$apply는 모든 스코프의 모든 바인드 값에 대해 더티 체크(변경 검출을 위한 각도 방식)를 수행합니다.이는 특히 바인딩이 많은 경우 고가의 퍼포먼스가 될 수 있습니다. $scope.$digest 는 의 「」, 「」, 「」, 「」의 범위내의 합니다.$scope훨씬 더 퍼포먼스가 뛰어납니다.

이것은, 내선 번호에 의해서 간단하게 실시할 수 있습니다.

class SomeController {
  constructor($async) {
    this.testAsync = $async(this.testAsync.bind(this));
  }

  async testAsync() { ... }
}

보시다시피 약속 반환 기능을 나중에 호출하는 래퍼로 감싸는 것이 전부입니다.

를 자동적으로 하는 할 수 있는 .async가 모두 됩니다.Promise원어민에게는 할 수 있는 .asyncTypeScript)es2017target하며, "target"은 "target"이 아니기 Promise 으로 예상되는 동작이 때문에 수 없다는 입니다.더 중요한 것은 이 방법은 기본적으로 예상되는 동작이 아니기 때문에 받아들일 수 없다는 것입니다.개발자는 이를 완전히 제어하고 이 동작을 명시적으로 할당해야 합니다.

testAsync번 , 되는 유일한 는 ""입니다.testsAsync의, "Diagnost"testAsync 스팸이 됩니다 방법은 를 한 번 이지만, 그 에 다이제스트를 트리거하면 됩니다.testsAsync.

경우, 「 」$async만 적용되다testsAsync testAsync 자체 명령어:

class SomeController {
  constructor($async) {
    this.testsAsync = $async(this.testsAsync.bind(this));
  }

  private async testAsync() { ... }

  async testsAsync() {
    await Promise.all([this.testAsync(1), this.testAsync(2), ...]);
    ...
  }
}

각도 비동기 대기의 코드를 조사해 보니$rootScope.$apply()비동기 약속이 해결된 후 표현을 다이제스트합니다.

이치노Angular Angular를할 수 . 오리지널 JS ★★$q약간의 트릭으로 최고의 퍼포먼스를 얻을있습니다.

먼저 기능(공장, 방법 등)을 만듭니다.

// inject $q ...
const resolver=(asyncFunc)=>{
    const deferred = $q.defer();
    asyncFunc()
      .then(deferred.resolve)
      .catch(deferred.reject);
    return deferred.promise;
}

이제 인스턴스 서비스용으로 에서 사용할 수 있습니다.

getUserInfo=()=>{

  return resolver(async()=>{

    const userInfo=await fetch(...);
    const userAddress= await fetch (...);

    return {userInfo,userAddress};
  });
};

이는 Angular를 사용하는 것만큼 효율적입니다.JS$q소한최

네이티브 ES6는 @basarat이 말했듯이Promise다이제스트 사이클을 모르기 때문에

해서 가 타이프스크립트를 사용하게 할 수 .$qES6에 대해서입니다.

발음을 하지 될 것 같아요.$scope.$apply()

angular.module('myApp')
    .run(['$window', '$q', ($window, $q) =>  {
        $window.Promise = $q;
    }]);

내가 원하는 행동을 보여주는 바이올린을 설치했어.여기서 알 수 있다: 각진과의 약속JS. 1000ms 후에 해결되는 Promise, 비동기 함수 및 Promise.race를 사용하고 있으며 여전히 4개의 다이제스트 사이클만 필요합니다(콘솔 열기).

원하는 행동이 무엇이었는지 다시 한 번 말씀드리겠습니다.

  • 네이티브 JavaScript와 마찬가지로 비동기 기능을 사용할 수 있도록 합니다.이것은 다른 서드파티 라이브러리가 없다는 것을 의미합니다.$async
  • 최소 다이제스트 사이클 수를 자동으로 트리거합니다.

이것은 어떻게 달성되었습니까?

ES6에서는 Proxy라는 멋진 기능이 제공되었습니다.이 개체는 기본 작업(예: 속성 검색, 할당, 열거, 함수 호출 등)에 대한 사용자 지정 동작을 정의하는 데 사용됩니다.

즉, Promise를 Proxy로 랩할 수 있으며, Promise가 해결되거나 거부되면 필요한 경우에만 다이제스트 사이클이 트리거됩니다.다이제스트 사이클을 트리거하는 방법이 필요하기 때문에 이 변경은 Angular에 추가됩니다.JS 실행 시간

function($rootScope) {
  function triggerDigestIfNeeded() {
    // $applyAsync acts as a debounced funciton which is exactly what we need in this case
    // in order to get the minimum number of digest cycles fired.
    $rootScope.$applyAsync();
  };

  // This principle can be used with other native JS "features" when we want to integrate 
  // then with AngularJS; for example, fetch.
  Promise = new Proxy(Promise, {
    // We are interested only in the constructor function
    construct(target, argumentsList) {
      return (() => {
        const promise = new target(...argumentsList);

        // The first thing a promise does when it gets resolved or rejected, 
        // is to trigger a digest cycle if needed
        promise.then((value) => {
          triggerDigestIfNeeded();

          return value;
        }, (reason) => {
          triggerDigestIfNeeded();

          return reason;
        });

        return promise;
      })();
    }
  });
}

★★async functions「Promise to work」(약속)에 의존해, 몇줄의 코드로 소기의 동작을 실현했습니다.추가 기능으로 기본 Promise를 Angular로 사용할 수 있습니다.JS!

나중에 편집:이 동작은 일반 JS를 사용하여 복제할 수 있으므로 프록시를 사용할 필요가 없습니다.여기 있습니다.

Promise = ((Promise) => {
  const NewPromise = function(fn) {
    const promise = new Promise(fn);

    promise.then((value) => {
      triggerDigestIfNeeded();

      return value;
    }, (reason) => {
      triggerDigestIfNeeded();

      return reason;
    });

    return promise;
  };

  // Clone the prototype
  NewPromise.prototype = Promise.prototype;

  // Clone all writable instance properties
  for (const propertyName of Object.getOwnPropertyNames(Promise)) {
    const propertyDescription = Object.getOwnPropertyDescriptor(Promise, propertyName);

    if (propertyDescription.writable) {
      NewPromise[propertyName] = Promise[propertyName];
    }
  }

  return NewPromise;
})(Promise) as any;

Angular에서 업그레이드하는 경우ngUpgrade를 사용하여 JS에서 Angular로 이동(https://angular.io/guide/upgrade#upgrading-with-ngupgrade):

Zone.js는 네이티브 약속에 패치를 적용하므로 모든 $q 기반 Angular 재작성을 시작할 수 있습니다.JS는 Microtask 큐가 비어 있을 때(예: Promise가 해결되었을 때) 자동으로 $digest를 트리거하므로 기본 Promise에 약속합니다.

Angular로 업그레이드 할 계획이 없는 경우에도 프로젝트에 Zone.js를 포함시키고 ngUpgrade와 같은 훅을 설정함으로써 동일한 작업을 수행할 수 있습니다.

$scope에 수동으로 전화할 필요가 없는 회피책이 있습니까?매번 $syslog()?

이는 TypeScript가 브라우저 네이티브를 사용하기 때문입니다. Promise앵글 1.x로 하다제어하지 않는 모든 비동기 함수를 더티 체크하려면 다이제스트 사이클을 트리거해야 합니다.

@basarat가 말했듯이 ES6 Promise는 다이제스트 사이클을 모른다.당신은 약속해야 한다.

async testAsync() {
 await this.$timeout(2000).toPromise()
      .then(response => this.text = "Changed");
 }

이미 설명한 바와 같이 angular는 언제 네이티브 Promise가 완료되었는지 알 수 없습니다. ★★★★★async는 새로운 .Promise.

생각할 수 있는 해결책은 다음과 같습니다.

window.Promise = $q;

이 방법으로 TypeScript/Babel은 각진 약속을 대신 사용합니다.그것은 안전한가요?솔직히 잘 모르겠어요.아직도 이 솔루션을 테스트하고 있어요.

일반적인 공장에서 변환 함수를 작성하려고 합니다(이 코드는 테스트하지 않았지만 작동해야 합니다).

function toNgPromise(promise)
{
    var defer = $q.defer();
    promise.then((data) => {
        $q.resolve(data);
    }).catch(response)=> {
        $q.reject(response);
    });

    return defer.promise;
}

이건 단지 당신을 시작하기 위한 것일 뿐이지만, 결국 변환이 이렇게 간단하지는 않을 거라고 생각합니다.

언급URL : https://stackoverflow.com/questions/39943937/typescript-async-await-doesnt-update-angularjs-view