비동기식 - 대기 중

33295 단어 programmingjavascript

비동기식 대기 키워드
  • 비동기식 대기 방식
  • 약속
  • 에 비해
  • 사용 예제
  • 트랩
  • 본고에서 나는 비동기 대기 구조가 어떻게 작동하는지 탐색하고 해석할 것이다.
    이것은 코드에 어떤 영향을 미치고 표준 자바스크립트의 약속에 비해 어떤 영향을 미치는가.
    그리고 두 가지 예시를 통해Promise를 사용할 때 코드의 외관과 async await 키를 사용할 때 코드의 외관을 보여 드리겠습니다.
    이 두 가지 인코딩 스타일을 사용할 때, 나는 함정과 까다로운 부분을 언급할 것이다.
    관련 문서와 규범에 대한 링크를 드리겠습니다.

    소개하다.
    Async-await는 비동기 흐름을 간소화하기 위해 2017년에 Ecmascript 규범을 도입했다.

    기본 원칙과 규칙
    비동기 함수는 다음과 같이 키워드 async로 정의됩니다.
    async myFunction() {
      // body of the function
    }
    
    비동기 스타일 함수에 대한 서명은 다음과 같습니다.
    ([...any]): Promise<any>
    
    async 함수는 어느 곳에서든 호출할 수 있지만, async 블록에서만 await 키워드를 사용할 수 있습니다.
    async myFirstFunction() {
      // some logic
      const partial = await getParialResult(); // calling another async function or function returning promise
      // other logic
      return processPartial(partial) // calling sync function with non promise parameter returning non promise value
    }
    
    부분some logic은 동기화되어 실행되었다.부분other logic비동기 함수 호출 getParial Result 가 해결되었습니다.

    약속과의 관계
    표준 함수와 비동기 함수의 차이는 비동기 함수가 항상 자바스크립트Promise 대상을 되돌려준다는 데 있다.
    이 점에 관해서는 거의 아무런 기본 규칙이 없다.

    정의되지 않은return문
    그 중에서 표준 함수 반환undefined값, 비동기 함수 반환Promise<undefined>-공약 해석undefined.
    async myFunction() {
      console.log('hi from async function')
    }
    

    함수 반환(편집 불가) 값
    만약return문장이 존재하고 반환값이 aPromise와 notundefined가 아니라면 이 값은 해석된 Promise문장에 포장됩니다
    그리고 돌아왔습니다.
    async function myFunction() {
      ...
      return 'hello world'
    }
    
    myFunction() // Promise { 'hello world' }
    
    이와 유사한 동작은 다음과 같습니다.
    function myFunction() {
      return Promise.resolve('hello world')
    }
    

    함수 반환 테이블 값promise 또는promise-like 대상
    마지막 사례는 이전 사례의 자집에 불과하지만 특별히 언급할 만하다.
    비동기 함수가 Promise를 반환합니다.이런 상황에서 통역사는 다시 비슷한 일을 하지만 미묘하지만 중요한 차이가 있다.
    [thenable] 객체가 발견되면 내포된 레이어가 자동으로 벤드펴집니다.이것은 비동기 함수가 되돌아오는 상황이 아니다.여기서 프로미스에서 포장된 값이 전개되어 새로운 프로미스 대상에 다시 포장됩니다.
    약속에 비하다.결심:
    const myPromise = new Promise((resolve, reject) => { resolve(42) });
    async function myAsyncFunction() { return myPromise }
    
    var p = myFunction()
    // p is holding Promise { 42 }
    
    p === myPromise // false
    myPromise === Promise.resolve(myPromise) // true, because the nested structure is flattened
    
    표준 기능과 비교:
    function mySyncFunction() { return myPromise }
    
    var p = myFunction()
    // p is holding Promise { 42 }
    
    p === myPromise // true
    
    비동기 함수에서 해석 약속이 포함된 값을 반환하는 동작을 시뮬레이션하면 다음과 같이 작성할 수 있습니다.
    function likeAsyncFunction() {
      // value inside promise is unwrapped and wrapped again in new promise object
      return myPromise.then(value => Promise.resolve(value))
    }
    p = likeAsyncFunction() // Promise { 42 }
    
    myPromise === p // false
    

    그럼, 그것은 단지 문법상의 설탕일 뿐입니까?
    내가 가장 먼저 생각한 것은 견지하는 것이다. 이것은 단지 약속한 문법적 당분일 뿐이다.Promise.resolve 키워드 뒤에 존재하는 모든 내용을 await 프로세서에 들어갈 수 있습니다.이거 진짜예요?
    약속의 유사성과 차이를 설명할 수 있는 예는 드물다. 약속 이외의 이종 대기 구조를 어떻게 탐색할 수 있는지에 대한 생각이나 개념을 줄 수도 있다.

    동기와 비동기 부분
    나는 아래의 예시에서 전형적인 비동기 함수의 성질을 설명할 것이다.이것은 nodejs에서 실행할 수 있습니다.
    // app.js
    // run node app.ja
    
    /*
     * this function will be used trhought few more examples, so keep it.
     * when using plain promises the async keyword can be ignored (ref. to the above explanation)
     */
    async function sleep(mls) {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log('resolving...')
          resolve(mls)
        }, mls)
      })
    }
    
    async function serviceB() {
      console.log('serviceB:1');
      await sleep(1000)
      console.log('serviceB:2')
    }
    
    async function serviceA() {
      console.log('serviceA:1')
      await serviceB()
      console.log('serviceA:2')
    }
    
    console.log('before')
    serviceA();
    console.log('after')
    
    상기 코드는 다음과 같은 출력을 생성할 것이다
    before
    serviceA:1
    serviceB:1
    after
    resolving...
    serviceB:2
    serviceA:2
    
    서비스A가 일반 함수로 호출되었습니다.동기화를 계속합니다.
    서비스 A 내부에서 서비스 B에 대한 함수 호출을 통해 첫 번째wait 키워드를 얻을 수 있습니다.현재 이 함수 서비스 B를 분석하고 실행합니다.
    반환 (Promise) 이나 다른 대기 함수 호출을 찾을 때까지 창고로 전송되고 동기화됩니다.
    호출을 기다린 후 함수의 나머지 부분에 무슨 일이 일어났습니까?
    그것은 리셋과 유사한 또 다른 코드 블록으로 여겨진다.비동기식 작업이 완료되면 블록은 대기열에 서서 스택으로 돌아갑니다.
    이것은 사용 승낙에 매우 가까운 등가물이다.
    function serviceB() {
      console.log('serviceB:1');
      return new Promise(resolve => {
        sleep(1000).then(() => {
          console.log('serviceB:2')
          resolve();
        })
      })
    }
    
    function serviceA() {
      console.log('serviceA:1')
      return new Promise((resolve) => {
        serviceB().then(() => {
          console.log('serviceA:2')
          resolve();
        })
      })
    }
    
    console.log('before')
    serviceA();
    console.log('after')
    
    이전 코드와 완전히 같은 방식으로 실행하면 완전히 같은 출력이 발생합니다.콘솔 로그 프레젠테이션
    함수 서비스A와 서비스B가 창고에 도착하면 창고에서 실행할 수 있도록 합니다 then.
    비동기적인 부분이 완성되면 리셋 또는 비동기적인 코드 블록을 창고에 놓고 서비스B를 실행하고 리셋 또는 비동기적인 코드 블록을 창고에 놓고 서비스A를 실행합니다.
    그것이 어떻게 작동하는지 제외하고 이 두 가지 예는 앞에서 언급한 비동기 대기 구조의 장점 중 하나를 보여 준다.
    코드의 가독성이 더욱 높고, 리셋도 그다지 어지럽지 않다.
    그러나 어떤 사람들은 문법의 동기성이 혼란을 일으킬 수 있고 일부 오류는 추적하기 어렵다고 생각할 수도 있다.
    나 이게 무슨 뜻이야?
    serviceA()
    serviceB()
    serviceC()
    
    만약 이것들이 내부에wait가 있는 비동기 함수라면 함수의wait 부분에서 완성된 순서는 이 함수를 호출하는 순서와 무관하다.
    전통적인 방식으로 이 글을 쓰면 실제 행위를 더욱 촉진시킬 수 있다.
    serviceA().then(callbackA)
    serviceB().then(callbackB)
    serviceC().then(callbackC)
    
    장래의 곤혹을 피하기 위해서 사물이 어떻게 작동하는지 배우는 것은 항상 좋다.

    순환 및 유사
    for 순환에서 비동기 코드를 처리합니다. 특히 리셋이 순서대로 실행되어야 할 때 어려울 수 있습니다.
    사용console.log('after') 시 간단명료하게 보임
    async function update(earliestVersion, lastVersion)
    {
      for (i = earliestVersion; i <= lastVersion, i++) {
        try {
          await applyUpdate(`version_${first}`);
        } catch(e) {
          throw Error('Update Error')
        }
      }
    }
    
    // possible usage in the code:
    update(12, 16)
      .then(handleSuccess)
      .catch(handleError)
      .finally(handleFinish)
    
    약속에 기초한 대체 방안이 비슷한 역할을 할 수도 있다.
    논리가 어떻게 흐르는지 아직 잘 모르며, 어디에 있는지, 이상과 고장을 어떻게 처리하는지는 말할 것도 없습니다.
    function update(earliestVersion, lastVersion) {
      function _update(version){
        return applyUpdate(version)
          .then((res) => {
            if (version <= lastVersion) {
              return _update(version + 1)
            } else {
              return res;
            }
          })
          .catch(() => { throw Error('Update Error') })
      }
      return _update(version)
    }
    

    WHILE loop과 비슷한 거.
    이것은 for 순환의 상황과 유사하다.만약 우리가 풍전장 중심을 운행하고 있다면 서버는 풍력 터빈의 상태를 보고해야 한다.
    열악한 날씨 상황에서 서버는 이 상태를 검색하거나 최대 시도 횟수에 도달할 때까지 풍력 터빈의 상태를 계속 물어봐야 한다.
    async function reportStatus(nu) {
      let status = false;
      let tries = 0;
      while (!status) {
        await status = getTurbineStatus(nu)
        logStatusCall(no, status, tries++)
      }
      return status;
    }
    // usage
    turbines.forEach(reportStatus)
    
    // or
    Promses.allSettled(turbines.map(reportStatus))
    .then(handleResponses)
    
    for-loop과 유사하게 공약을 사용하여 작성하고 테스트하는 것은 더욱 도전적일 것이다
    function reportStatus(nu) {
      let status = false;
      let tries = 0;
      function _helper(n){
        return getTurbineStatus(n).then((status) => {
            logStatusCall(no, status, tries++)
            if (!status) {
              return _helper(n);
            } else {
              return status
            }
          })
      }
      return _helper(nu)
    }
    

    발전기의 기능은 어떻습니까?
    생성기 함수와 async 키워드를 조합할 수 있습니까?어느 정도 옳고 그름.
    다음은 간단한 카운트다운 함수의 예이다.setTimeout을 사용하고 있습니다.
    async function* countdown(count, time) {
        let index = count;
    
        while (index) {
            await sleep(time)
            yield --index;
        }
    }
    
    async function testCountDown(count) {
      const cd = countdown(4, 1000)
      let val = await cd.next();
      while (!val.done) {
        console.log(`finish in ${val.value}`)
        val = await cd.next();
      }
      console.log('...finished')
    }
    
    testCountDown(5)
    
    동기 발전기의 기능과 비교하면 관건적인 차이가 있다.그것은 사실상 교체 프로토콜을 파괴했다.
    비동기 함수는 항상 약속을 되돌려주기 때문에 예상 대상async-await은 약속에 포장됩니다.
    그것도 { value, done } 순환에 적용되지 않고 확장 연산자for..of에도 적용되지 않는다.
    이 두 가지 구조는 모두 [...iterable]가 필요하지만 해석기는 직접 접근할 수 없다iterable 대상.
    나의 조언은 async generator 함수를 사용하지 않는 것이다. 만약 정말 그것을 사용해야 한다면, 그것들 사이의 차이를 주의하여 의외의 행위와 오류를 피하십시오.

    비동기 함수를 일종의 방법으로 삼다
    방법은 대상에 귀속된 함수다.그렇다면 비동기 함수는 하나의 방법으로서 어떻게 일을 하는가, 전통 함수에 비해 어떻게 일을 하는가?
    비동기 함수도 이곳의 절차를 간소화시켰다.promise handler의 promise와 달리 키워드{ value, done }는 호출 대상을 가리키며 this 키워드 뒤에 있는 블록의 비동기적인 부분을 가리킨다.promise 프로세서 내부에서 인용하기 await 는 화살표 함수나 귀속 this 을 사용해야 합니다.
    예:
    function logName() {
      console.log(`Hi, my name is ${this.name}.`)
    }
    
    class Simpson {
      constructor(name) {
        this.name = name
      }
      logName() {
        console.log(`Hi, my name is ${this.name}.`)
      }
      async waitAndSayHi(time) {
        await sleep(time);
        this.logName();
      }
      waitAndSayHiWithPromise(time) {
        return new Promise(resolve => {
          sleep(time).then(this.logName.bind(this))
        })
      }
    }
    
    const lisa = new Simpson('Lisa')
    const bart = new Simpson('Bart')
    
    lisa.waitAndSayHi(500)
    bart.waitAndSayHiWithPromise(1000)
    
    생략this은 뚜렷한 오류를 초래하고 원인이 뚜렷하다..bind(this)를 사용할 때 우리는 걱정할 필요가 없는 일이다.

    요약
    async-await는 비동기 코드를 처리하는 간편한 방법이다.그것은 흐름 제어에 도움이 되며, 여러 개의 비동기 조작 서열이 필요한 순환에 특히 유용하다.
    만약 프로그래머가 결과를 충분히 의식한다면, 그것은 코드의 가독성을 높일 수 있다.
    그것은 약속의 문법사탕이 아니라 약속 구조의 확장으로 여겨져야 한다.

    출처
  • Async Function Definition
  • Generator
  • Async-Await MDN
  • 좋은 웹페이지 즐겨찾기