1. 程式人生 > 實用技巧 >Part2.非同步程式設計

Part2.非同步程式設計

文章內容輸出來源:拉勾教育大前端訓練營

非同步程式設計

  • Javascript語言的執行環境是單執行緒,一次只能完成一件任務,必須排隊.js同步執行載入大資料及運行復雜演算法導致頁面的白屏時間過長,瀏覽器假死現象.會帶來不好的使用者體驗.而非同步程式設計解決了這一個問題,不在等待返回.而是等到有返回值有的時候或者該執行的時候進入訊息佇列中等待被呼叫.
  • 非同步程式設計的基礎方法就是回撥函式,其他方法還有事件監聽,資訊釋出/訂閱,Promise,Generator,async/awit,setTimeOut/setInterval
  • 非同步程式設計最好的例子就是AJAX

同步模式

  • 概述:單執行緒模式下都是同步執行程式碼的.
  • 問題:排隊執行,會阻塞執行佇列.

非同步模式

  • 概述: 非同步執行不會等待任務結束,開啟過後立即開啟下一個任務,通過回撥函式執行後續邏輯業務.同時處理大量的耗時任務.
  • 問題: 程式碼的執行順序混亂,不利於閱讀

回撥函式

  • 概述:非同步程式設計的基本用法

Promise 承諾

  • 概述:一個物件,表述一個任務成功(fulfilled)或者失敗(rejected).狀態不可更改.解決回撥地獄問題
  • 問題:巢狀呼叫,使用.then 來避免 傳統的回撥地獄問題.實現程式碼的扁平化
code
const promise = new Promise(function (resolve, reject) {
  resolve(100);
//   reject(new Error("promise rejected"));
});

promise.then(
  function (value) {
    console.log("resolved", value);
  },
  function (error) {
    console.log("rejected", error);
  }
);

promise 異常捕獲
  1. 鏈式呼叫.catch()捕獲異常,可以傳遞錯誤資訊
  2. 在.then內部註冊onrejected事件只能捕獲當前promise的異常
  3. 全域性註冊 unhandledrejection 處理沒有被捕獲的錯誤資訊(不推薦使用)
code

function ajax(url) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", url);
    xhr.responseType = "jsonp";
    xhr.onload = function () {
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    xhr.send();
  });
}

// ajax("./code/mock.json").then(
//   function (res) {
//     console.log(res);
//   },
//   function (err) {
//     console.log(err);
//   }
// );
ajax("./code/mock.json")
  .then(function (res) {
    console.log(res);
  })
  .catch(function (err) {
    console.log(err);
  });

promise 靜態方法
  1. resolve 快速建立成功狀態的promise物件
  2. reject 快速建立失敗狀態的promise物件
promise 並行請求
  • all 同步並行執行 等待所有組合的任務++成功++結束
  • race 並行執行 只會等待第一個執行任務完成
promise 執行順序
  • 巨集任務 任務完成後 其他業務邏輯重新排隊執行
  • 微任務 任務完成 其他業務邏輯立即執行
Generator 生成器 扁平化非同步呼叫
  • 概述:
      • 代表 Generator函式;
    1. next()執行函式體;
    2. yield關鍵詞,暫停生成器執行,直到外部.next()再執行後面的語句.yield後面的值作為返回物件的value值返回
    3. throw() 丟擲異常
code
// function* main() {
//   try {
//     console.log('start');
//     const msg = yield "log1";
//     console.log(msg);
//     const msg1 = yield "log2";
//     console.log(msg1);
//     const msg2 = yield "log3";
//     console.log(msg2);
//   } catch (error) {
//     console.log("main:" + error);
//   }
// }

// const g = main()
// const g1=g.next("233")
// console.log(g1)
// g.next("234")
// g.throw("error")

//genterator 配合promise 非同步執行
function* main() {
  try {
    console.log("start");
    const ajax1 = yield Promise.resolve("msg1");
    console.log(ajax1);
   
    const ajax2 = yield Promise.resolve("msg2");
    console.log(ajax2);
  } catch (error) {
    console.log("main:" + error);
  }
}

// const g = main();
// const result = g.next();
// result.value.then((data) => {
//   const result1 = g.next(data);
//   if (result1.done) return;
//   result1.value.then((data) => {
//     const result2 = g.next(data);
//     if (result2.done) return;
//     result2.value.then((data) => {
//         const result3 = g.next(data);
//         if (result3.done) return;
//       });
//   });
// });

//封裝 生成器函式呼叫
function co(generator) {
  const g = generator();
  function handleResult(result) {
    console.log(result);
    if (result.done) return;
    //   console.log(result.value);
    result.value
      .then((data) => {
        handleResult(g.next(data));
      })
      .catch((err) => console.log(err));
  }
  handleResult(g.next());
}
co(main);