비동기 솔루션의 Promise 및 async/await

49009 단어 학습 노트

비동기 솔루션의 Promise 및 async/await

  • Promise 객체
  • 약속이 필요하다는 사실이 증명된다
  • Promise.all
  • Promise.race
  • async 함수
  • Promise 객체


    비동기와 동기화에 비해 가장 통제하기 어려운 것은 비동기의 임무가 언제 완성되고 완성된 후의 리셋 문제다.
    장악하기 어려운 촉발 상태는 당신이 쓴 코드를 그때는 읽을 수 있었지만 며칠 보름이 지난 후에 논리를 다시 펼치지 않으면 어떤 내용이 먼저 이런 예를 빌려쓰는지 어떻게 알겠는가
    document.addEventListener('click', function handler(evt) {
    	setTimeout(function () {
    		ajax('some.url', function(txt) {
    			if(txt == 'hello') {
    				handler()
    			} else {
    				request()
    			}
    		})
    	}1000)
    })
    

    listern 먼저 실행()
    다음 DoSomething()
    500ms (또는 더 먼 곳) 후 aax () 실행
    ajax 완료 후
    만약 text = = hello가handler () 를 실행한다면
    만약 text==world가 Request()를 실행한다면
    아파요???

    사실은 네가 승낙이 필요하다는 것을 증명한다


    당신이 한 가지 일을 다른 사람에게 맡기면 (금방 완성할 수도 있고 시간이 걸릴 수도 있다) 이 사람은 임무를 완수하거나 실패한 후에 당신에게 대답을 한다. 이런 사람은 당신이 특별히 안심하고 일을 그에게 맡기지 않는가. 그가 당신에게 대답하지 않으면 그는 일을 하고 있다. 대답하면 성공하거나 실패한다.
    자바스크립트에서 이런 사람이 프로미스예요.
    Pending(진행 중), Resolved(완료), Rejected(거부됨) 등 세 가지 상태가 있습니다.프로미스에게 한 가지 일을 맡겼을 때 그 상태는 펜딩이다. 임무를 완성한 상태는 Resolved가 되고, 완성하지 못한 상태는 Rejected가 된다.
    본론으로 돌아가다: 간단한 프로미스를 쓰다
    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/*   */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    

    Promise가 실행하는 내용이 예상한 성공 조건에 부합되면 Resolve 함수를 호출하고, 실패하면 Reject 함수를 호출합니다. 이 두 함수의 매개 변수는 Promise에 포착됩니다.이후 콜백에서 사용할 수 있다.
    공약을 만듭니다. 우리는 이미 다 했습니다. 그러면 공약의 결과를 어떻게 사용합니까?
    promise.then(res=>
    	{console.log(res);// resolve 
    },err=>{
    	//  reject 
    	console.log(err);
    })
    

    예1
    function loadImageAsync(url) {
      return new Promise(function(resolve, reject) {
        const image = new Image();
    
        image.onload = function() {
          resolve(image);
        };
    
        image.onerror = function() {
          reject(new Error('Could not load image at ' + url));
        };
    
        image.src = url;
      });
    }
    

    예2
    const getJSON = function(url) {
      const promise = new Promise(function(resolve, reject){
        const handler = function() {
          if (this.readyState !== 4) {
            return;
          }
          if (this.status === 200) {
            resolve(this.response);
          } else {
            reject(new Error(this.statusText));
          }
        };
        const client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();
    
      });
    
      return promise;
    };
    
    getJSON("/posts.json").then(function(json) {
      console.log('Contents: ' + json);
    }, function(error) {
      console.error(' ', error);
    });
    

    n 방법은 두 개의 함수를 받아들인다. 첫 번째는 성공을 약속하는 리셋 함수이고, 하나는 실패를 약속하는 리셋 함수이다.
    n 방법은 새로운 Promise 실례를 되돌려줍니다. (원래 그 Promise 실례가 아닙니다.)따라서 체인식 쓰기, 즉then 방법 뒤에 다른then 방법을 사용할 수 있다.
    let p = new Promise((resolve, reject) => {
        setTimeout(resolve, 1000, 'success');
    });
    p.then(
        res => {
            console.log(res);
            return new Promise((resolve, reject) => {
                setTimeout(resolve, 1000, 'success');
            });
        }
    )
        .then(
            res => console.log(res)
        );
    

    말이 직렬 로 끝났으니 병렬 은 어떻게 하나요???여러 개의 비동기적인 사건이 있을 때, 사이에는 아무런 연관이 없고, 선후 순서가 없으면, 전부 완성하기만 하면 일을 시작할 수 있다.
    직렬은 모든 비동기 이벤트의 대기 시간을 합쳐서 완성에 대한 차단을 뚜렷하게 한다.그럼 병행하면 어떻게 다 완성할 수 있을까요?

    Promise.all


    Promise.all는 하나의 그룹을 수신합니다. 그룹의 모든 항목은promise 대상입니다.
    const p = Promise.all([p1, p2, p3]);
    

    그룹의 모든promise의 상태가 Resolved에 도달했을 때Promise.all의 상태는 Resolved가 되고, 하나의 상태가 Rejected가 되면Promise.all의 상태는 Rejected (임의의 실패는 실패라고 해도) 로 변합니다. 이것은 우리가 병행하는 문제를 해결할 수 있습니다.then 방법을 호출할 때 결과가 성공할 때 리셋 함수의 매개 변수도 하나의 수조로 각promise 대상의resolve가 실행될 때의 값을 순서대로 저장합니다.
    const p1 = new Promise((resolve, reject) => {
      resolve('hello');
    })
    .then(result => result)
    .catch(e => e);
    
    const p2 = new Promise((resolve, reject) => {
      throw new Error(' ');
    })
    .then(result => result)
    .catch(e => e);
    
    Promise.all([p1, p2])
    .then(result => console.log(result))
    .catch(e => console.log(e));
    

    Promise.race


    Promise.레이스 스피드 경쟁 모드도 하나하나가 프로미스의 수조를 받아들인다.
    const p = Promise.all([p1, p2, p3]);
    

    그러나 all와 달리 첫 번째 promise 대상의 상태가 Resolved로 변할 때 자신의 상태가 Resolved로 변하고, 첫 번째 promise가 Rejected 자체의 상태가 Rejected로 변한다.첫 번째로 Resolved가 된promsie의 값이 사용됩니다.
    const pro1 = new Promise((resolve, reject) => {
    	setTimeout(resolve, 1000, 1)
    })
    
    const pro2 = new Promise((resolve, reject) => {
    	setTimeout(resolve, 2000, 2)
    })
    
    const pro3 = new Promise((resolve, reject) => {
    	setTimeout(resolve, 3000, 3)
    })
    
    Promise.race([pro1, pro2, pro3]).then(res => {
    	console.log(res)
    }, err => {
    	console.log('reject')
    	console.log(err)
    })
    // 1
    

    async 함수


    (1) 기본적으로 async 함수를 사용하여Promise 대상을 되돌려주고then 방법으로 리셋 함수를 추가할 수 있다.함수가 실행될 때, await를 만나면 먼저 되돌아오고, 비동기적인 조작이 완성될 때까지 기다린 다음에 함수 체내 뒤의 문장을 실행한다.
    다음은 하나의 예다.
    async function getStockPriceByName(name) {
      const symbol = await getStockSymbol(name);
      const stockPrice = await getStockPrice(symbol);
      return stockPrice;
    }
    
    getStockPriceByName('goog').then(function (result) {
      console.log(result);
    });
    

    위 코드는 주식 가격을 얻는 함수로 함수 앞의 async 키워드로 이 함수 내부에 비동기적인 조작이 있음을 나타낸다.함수를 호출하면 Promise 객체가 즉시 반환됩니다.
    다음은 몇 밀리초를 지정한 후에 값을 출력하는 또 다른 예이다.
    function timeout(ms) {
      return new Promise((resolve) => {
        setTimeout(resolve, ms);
      });
    }
    
    async function asyncPrint(value, ms) {
      await timeout(ms);
      console.log(value);
    }
    
    asyncPrint('hello world', 50);
    

    async 함수는 여러 가지 사용 형식이 있다.
    //  
    async function foo() {}
    
    //  
    const foo = async function () {};
    
    //  
    let obj = { async foo() {} };
    obj.foo().then(...)
    
    // Class  
    class Storage {
      constructor() {
        this.cachePromise = caches.open('avatars');
      }
    
      async getAvatar(name) {
        const cache = await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`);
      }
    }
    
    const storage = new Storage();
    storage.getAvatar('jake').then();
    
    //  
    const foo = async () => {};
    

    (2) Promise 객체 async 함수를 반환하고 Promise 객체를 반환합니다.
    async 함수 내부return 문장에서 되돌아오는 값은then 방법 리셋 함수의 매개 변수가 됩니다.
    async function f() {
      return 'hello world';
    }
    
    f().then(v => console.log(v))
    // "hello world"
    

    위 코드에서 함수 f 내부return 명령이 되돌아오는 값은 then 방법의 리셋 함수에 의해 수신됩니다.
    async 함수 내부에서 오류가 발생하면 되돌아오는 Promise 대상이 Reject 상태가 됩니다.던진 오류 대상은catch 방법의 리셋 함수에 의해 수신됩니다.
    async function f() {
      throw new Error(' ');
    }
    
    f().then(
      v => console.log(v),
      e => console.log(e)
    )
    // Error:  
    

    (3) await 명령이 정상적인 경우 await 명령 뒤에는 Promise 대상이 있고 그 대상의 결과를 되돌려줍니다.Promise 객체가 아니면 해당 값을 반환합니다.
    async function f() {
      //  
      // return 123;
      return await 123;
    }
    
    f().then(v => console.log(v))
    // 123
    

    위 코드에서 await 명령의 매개 변수는 수치 123입니다. 이때는return 123과 같습니다.
    또 다른 상황은 await 명령 뒤에 thenable 대상 (즉 then 방법을 정의하는 대상) 이 있다면 await는 이를 Promise 대상과 동일시할 것이다.
    class Sleep {
      constructor(timeout) {
        this.timeout = timeout;
      }
      then(resolve, reject) {
        const startTime = Date.now();
        setTimeout(
          () => resolve(Date.now() - startTime),
          this.timeout
        );
      }
    }
    
    (async () => {
      const actualTime = await new Sleep(1000);
      console.log(actualTime);
    })();
    

    위 코드에서 await 명령 뒤에는 Sleep 객체의 인스턴스가 있습니다.이 실례는 Promise 대상이 아니지만 then 방법을 정의했기 때문에 await는 이를 Promise 처리로 간주합니다.
    await 명령 뒤에 있는 Promise 대상이 Reject 상태로 바뀌면, Reject의 매개 변수는catch 방법의 리셋 함수에 의해 수신됩니다.
    async function f() {
      await Promise.reject(' ');
    }
    
    f()
    .then(v => console.log(v))
    .catch(e => console.log(e))
    //  
    

    위 코드에서 await 문장 앞에return이 없지만, Reject 방법의 매개 변수는catch 방법의 리셋 함수로 전송됩니다.여기에 await 앞에return을 더하면 효과가 같다.
    await 문장 뒤에 있는 Promise 대상이 Reject 상태로 바뀌면 전체 async 함수가 실행을 중단합니다.
    async function f() {
      await Promise.reject(' ');
      await Promise.resolve('hello world'); //  
    }
    

    위 코드에서 두 번째 await 문장은 실행되지 않습니다. 첫 번째 await 문장 상태가 Reject로 바뀌었기 때문입니다.
    때때로, 우리는 이전의 비동기 조작이 실패하더라도, 뒤의 비동기 조작을 중단하지 않기를 바란다.이 때 첫 번째 await를try...catch 구조에 넣으면 이 비동기적인 작업이 성공하든 안 하든 두 번째 await가 실행됩니다.
    async function f() {
      try {
        await Promise.reject(' ');
      } catch(e) {
      }
      return await Promise.resolve('hello world');
    }
    
    f()
    .then(v => console.log(v))
    // hello world
    

    또 다른 방법은 await 뒤에 있는 Promise 대상이 하나의catch 방법을 따라 앞에 발생할 수 있는 오류를 처리하는 것이다.
    async function f() {
      await Promise.reject(' ')
        .catch(e => console.log(e));
      return await Promise.resolve('hello world');
    }
    
    f()
    .then(v => console.log(v))
    //  
    // hello world
    

    좋은 웹페이지 즐겨찾기