Promise&async await

  • Promise: ES6 新增的語法,是異步問題同步化解決方案 ,同時解決了回調(diào)地獄的問題;

  • Promise解決:
    通過.then的方式,拿到Promise內(nèi)部的異步操作的結(jié)果,并且不阻塞 和Promise不相關(guān)的 任何程序,讓它們同步執(zhí)行;
    then 函數(shù)會返回一個 Promise 實例,并且該返回值是一個新的實例而不是之前的實例。因為 Promise 規(guī)范規(guī)定除了 pending 狀態(tài),其他狀態(tài)是不可以改變的,如果返回的是一個相同實例的話,多個 then 調(diào)用就失去意義了。 對于 then 來說,本質(zhì)上可以把它看成是 flatMap;

  • Promise的狀態(tài)(生命周期):
    padding:進行中
    fulfilled:已完成
    rejected:已失敗

  • 異步任務(wù)的完成與否 取決于當前 Promise的狀態(tài)
    1.異步任務(wù)完成 調(diào)用resolve()成功回調(diào) 狀態(tài):padding -> fulfilled
    2.異步任務(wù)失敗 調(diào)用reject()失敗回調(diào) 狀態(tài):padding -> rejected

  • Promise的特點:
    1.Promise的狀態(tài)不受外界的影響;
    因為Promise代表的是異步操作,只有異步操作成功或者或者失敗,才會改變* Promise的狀態(tài);
    2.Promise的狀態(tài)一旦改變就無法更改;
    一旦狀態(tài)固化,返回的結(jié)果在任何地方都調(diào)用的到;

  • Promise的執(zhí)行方式:
    微任務(wù)的方式執(zhí)行Promise注冊上回調(diào)函數(shù),不管是成功還是失敗都可以;
    微任務(wù):相當于高速中的緊急車道,可以讓微任務(wù)快速排在異步隊列的最前方,等待主線程通過事件輪詢將其調(diào)用;

  • Promise的靜態(tài)方法:(靜態(tài)方法是在構(gòu)造器中綁定的方法)
    Promise.resolve():返回一個成功狀態(tài)態(tài)的Promise,通過.then()注冊成功的回調(diào)函數(shù);
    Promse.reject():返回一個失敗狀態(tài)的Promise,通過.catch()注冊失敗的回調(diào)函數(shù);
    Promise.all([p1,p2,p3]):只有當中的Promise對象全部成功,才會返回一個結(jié)果且是個數(shù)組;
    Promise.race([p1,p2,p3]):返回其中一個運行最快的結(jié)果;

let p = new Promise((resolve,reject) => { //Promise中的回調(diào)函數(shù)是:執(zhí)行器函數(shù)(executon)===同步執(zhí)行
          console.log('我是Promise的同步回調(diào)函數(shù)');

          //異步任務(wù)
          $.ajax({ 
            url:'./data.json',
            success:function (data) {
              // console.log(data)
              resolve(data)
             
            },
            error:function (err) {
              reject(err)
            }
          })

        p.then((res) => { //.then方式注冊的是 成功的回調(diào)函數(shù)
          // console.log(res)
          // simpleArray(res)
          console.log( simpleArray(res))
        }).catch((err) => { //.catch方式注冊的是 失敗的回調(diào)函數(shù)
          console.log(err,'失敗')
        })

        console.log('我是同步代碼')

        function simpleArray (data) {
          return data.map(function (item) {
            // console.log(item)
            return item.name
          })
        }
// 我是Promise的同步回調(diào)函數(shù)
// 我是同步代碼
// ["zhangsan", "lisi", "wangwu"]
  • 面試考點:theable 對象
    1.Promise調(diào)用resolve方法傳入theable對象會發(fā)生什么?
    會調(diào)用theable對象中的 then方法,然后調(diào)用resolve()傳出成功結(jié)果,或者調(diào)用reject()傳出失敗結(jié)果;
    2.Promise調(diào)用reject方法傳入theable對象會發(fā)生什么?
    Promise只有調(diào)用resolve方法傳入theable對象才會返回成功或失敗的結(jié)果,
    調(diào)用reject()只會返回一個空對象{then:f}
        //theable 對象
        let obj = {
          then(resolve,reject){
            // resolve(11);
            reject(12);
          }
        }

        let p1 = Promise.resolve(obj);
        // let p1 = Promise.reject(obj);//{then:f}

        p1.then((data) => {
          console.log(data)
        }).catch((err) => {
          console.log(err)
        })
  • 案例
        //考察:異步隊列 事件輪詢 微任務(wù)
        Promise.resolve().then(function(){
          console.log('Promise1') //1
          setTimeout(() => {
            console.log('setTimeOut1') //4
          },0)
        })

        setTimeout(() => {
          console.log('setTimeOut2') //2
          Promise.resolve().then(function(){
            console.log('Promise2') //3
          })
        },0)
//Promise1
//setTimeOut2
//Promise2
//setTimeOut1

首先看出來,Promise是通過構(gòu)造函數(shù)實例化一個對象,然后通過實例對象上的then方法,來處理異步返回的結(jié)果。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function Promise(executor) {
    var _this = this
    this.state = PENDING; //狀態(tài)
    this.value = undefined; //成功結(jié)果
    this.reason = undefined; //失敗原因
    function resolve(value) {}
    function reject(reason) {}
}

Promise.prototype.then = function (onFulfilled, onRejected) {
};

module.exports = Promise;

當我們實例化Promise時,構(gòu)造函數(shù)會馬上調(diào)用傳入的執(zhí)行函數(shù)executor,我們可以試一下:

let p = new Promise((resolve, reject) => {
    console.log('執(zhí)行了');
});

因此在Promise中構(gòu)造函數(shù)立馬執(zhí)行,同時將resolve函數(shù)和reject函數(shù)作為參數(shù)傳入:

function Promise(executor) {
    var _this = this
    this.state = PENDING; //狀態(tài)
    this.value = undefined; //成功結(jié)果
    this.reason = undefined; //失敗原因
    function resolve(value) {}
    function reject(reason) {}
    executor(resolve, reject)
}

但是executor也會可能存在異常,因此通過try/catch來捕獲一下異常情況:

try {
    executor(resolve, reject);
} catch (e) {
    reject(e);
}
  • 手寫Promise
function Mypromise(fn) { //構(gòu)造函數(shù)
      this.state = 'pending' //狀態(tài)
      this.value = undefined //成功結(jié)果
      this.reason = undefined //失敗原因
      /*
      那么如何讓我們的Promise來支持異步呢?
      我們可以參考發(fā)布訂閱模式,在執(zhí)行then方法的時候,如果當前還是PENDING狀態(tài),
      就把回調(diào)函數(shù)寄存到一個數(shù)組中,當狀態(tài)發(fā)生改變時,去數(shù)組中取出回調(diào)函數(shù);
      */
      this.onFulfilled = [];//成功的回調(diào)
      this.onRejected = []; //失敗的回調(diào)

      let resolve = value => {
        if (this.state === 'pending') {
          this.state = 'fulfilled'
          this.value = value
          this.onFulfilled.forEach(fn => fn(value))
          // console.log(this.value)
        }
      }
      let reject = value => {
        if (this.state === 'pending') {
          this.state = 'rejected'
          this.reason = value
          this.onRejected.forEach(fn => fn(value))
          console.log(this.reason)
        }
      }
      // 自動執(zhí)行函數(shù) 
      try {
        fn(resolve, reject)
      } catch (e) {
        reject(e)
      }
      // then 

    }
     /*
      在規(guī)范中說明了,onFulfilled和onRejected是可選的,因此我們對兩個值進行一下類型的判斷:
      onFulfilled 和 onRejected 都是可選參數(shù)。
      如果 onFulfilled 不是函數(shù),其必須被忽略。
      如果 onRejected 不是函數(shù),其必須被忽略。
     */
    Mypromise.prototype.then = function (onFulfilled, onRejected) {
      if (this.state === 'fulfilled') {
        typeof onFulfilled === 'function' && onFulfilled(this.value)
      }
      if (this.state === 'rejected') {
        typeof onRejected === 'function' && onRejected(this.reason)
      }
      if (this.state === 'pending') {
        typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
        typeof onRejected === 'function' && this.onRejected.push(onRejected)
      }
    }
  
    //Promise:異步問題同步化解決方案
    let p = new Mypromise((resolve, reject) => { //Promise中的回調(diào)函數(shù)是:執(zhí)行器函數(shù)(executon)===同步執(zhí)行
      console.log('我是Promise的同步回調(diào)函數(shù)');

      //異步任務(wù)
      $.ajax({
        url: './data.json',
        success: function (data) {
          console.log(data)
          resolve(data)

        },
        error: function (err) {
          reject(err)
        }
      })
    })

  p.then((res) => { //.then方式注冊的是 成功的回調(diào)函數(shù)
      console.log(res)
      // simpleArray(res)
      console.log(simpleArray(res))
    })

   function simpleArray(data) {
      return data.map(function (item) {
        // console.log(item)
        return item.name
      })
    }
// 我是Promise的同步回調(diào)函數(shù)
// 我是同步代碼
// ["zhangsan", "lisi", "wangwu"]

手寫Promise參考原文:
從零開始手寫Promise
實踐系列-Promises/A+規(guī)范

  • 手寫Promise(用Class類)
 class myPromise {
      constructor(fn) {
        this.state = 'pending' //狀態(tài)
        this.value = undefined //成功結(jié)果
        this.reason = undefined //失敗原因

        this.onFulfilled = [];//成功的回調(diào)
        this.onRejected = []; //失敗的回調(diào)
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled'
            this.value = value
            this.onFulfilled.forEach(fn => fn(value))
            // console.log(this.value)
          }
        }
        let reject = value => {
          if (this.state === 'pending') {
            this.state = 'rejected'
            this.reason = value
            this.onRejected.forEach(fn => fn(value))
            console.log(this.reason)
          }
        }

        // 自動執(zhí)行函數(shù) 
        try {
          fn(resolve, reject)
        } catch (e) {
          reject(e)
        }
      }

      // then 
      then(onFulfilled, onRejected) {
        if (this.state === 'fulfilled') {
          typeof onFulfilled === 'function' && onFulfilled(this.value)
        }
        if (this.state === 'rejected') {
          typeof onRejected === 'function' && onRejected(this.reason)
        }
        if (this.state === 'pending') {
          typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
          typeof onRejected === 'function' && this.onRejected.push(onRejected)
        }
      }

    }

 //Promise:異步問題同步化解決方案
    let p = new myPromise((resolve, reject) => { //Promise中的回調(diào)函數(shù)是:執(zhí)行器函數(shù)(executon)===同步執(zhí)行
      console.log('我是Promise的同步回調(diào)函數(shù)');

      //異步任務(wù)
      $.ajax({
        url: './data.json',
        success: function (data) {
          console.log(data)
          resolve(data)

        },
        error: function (err) {
          reject(err)
        }
      })
    })

    p.then((res) => { //.then方式注冊的是 成功的回調(diào)函數(shù)
      console.log(res)
      // simpleArray(res)
      console.log(simpleArray(res))
    })

   function simpleArray(data) {
      return data.map(function (item) {
        // console.log(item)
        return item.name
      })
    }
// 我是Promise的同步回調(diào)函數(shù)
// 我是同步代碼
// ["zhangsan", "lisi", "wangwu"]
  • async & await:
    原理:async 和 await 用了同步的方式去做異步,async 定義的函數(shù)的返回值都是 promise,await后面的函數(shù)會先執(zhí)行一遍,然后就會跳出整個 async 函數(shù)來執(zhí)行后面js棧的代碼;
    主要考察宏任務(wù)和微任務(wù),搭配promise,詢問一些輸出的順序;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 不多說,這2個都是寫異步的沒毛病。 長期用,但從未系統(tǒng)梳理過,所以特此將它們的用法原理都整理下。下邊我會先梳理它們...
    南山碼僧閱讀 407評論 0 1
  • 簡單介紹下這幾個的關(guān)系為方便起見 用以下代碼為例簡單介紹下這幾個東西的關(guān)系, async 在函數(shù)聲明前使用asyn...
    _我和你一樣閱讀 21,499評論 1 24
  • 回調(diào)地獄 回調(diào)地獄嵌套多個方法調(diào)用會創(chuàng)建錯綜復(fù)雜的代碼,會難以理解與調(diào)試。當想要實現(xiàn)更復(fù)雜的功能時,回調(diào)函數(shù)也會存...
    Inlight先森閱讀 2,904評論 0 4
  • 閱讀本篇文章之前一定要明白異步解決方案和 http 的關(guān)系。異步是異步,http 是http。http 請求是一個...
    oNexiaoyao閱讀 489評論 0 0
  • 關(guān)于Js的promise、generator、async、await 第一章 前言 ? 大家都...
    Martain閱讀 1,079評論 0 6

友情鏈接更多精彩內(nèi)容