javascript異步解決方案

路過的朋友,能夠點個贊,關注一下~~~javascript

js異步解決的發展歷程:

回調函數----->peomise------>generator + co----->async + awaitjava

1. 解決方案之回調函數

回調函數能夠解決存在的異步問題,但回調函數分爲,同步與異步: node

enter description here

1.2 回調函數能夠解決異步問題

callback git

enter description here

回調函數自己是咱們約定俗成的一種叫法,咱們定義它,可是並不會本身去執行它,它最終被其餘人執行了。github

優勢:比較容易理解; 缺點:1.高耦合,維護困難,回調地獄;2.每一個任務只能指定一個回調函數;3.若是幾個異步操>做之間並無順序之分,一樣也要等待上一個操做執行結束再進行下一個操做。npm

下圖回調地獄 編程

enter description here

2. 解決方案之promise的使用

2.1 promise的定義

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。promise

參考dom

理解:異步

  • 沒有異步就不須要promise。
  • Promise自己不是異步,只是咱們去編寫異步代碼的一種方式

2.2 promise 的規範

Es6將promise歸入本身規範的時候,也遵循了一個相應的標準 — ``Promise A+規範。

將其概括爲4321規範

4:4大術語 3:3種狀態 2:2種事件 1:1個對象

2.2.1 四大術語

  1. 解決(fulfill):指一個 promise 成功時進行的一系列操做,如狀態的改變、回調的執行。雖然規範中用 fulfill 來表示解決,但在後世的 promise 實現多以 resolve 來指代之。

  2. 拒絕(reject):指一個 promise 失敗時進行的一系列操做。

  3. 終值(eventual value):所謂終值,指的是 promise 被解決時傳遞給解決回調的值,因爲 promise 有一次性的特徵,所以當這個值被傳遞時,標誌着 promise 等待態的結束,故稱之終值,有時也直接簡稱爲值(value)。

  4. 據因(reason):也就是拒絕緣由,指在 promise 被拒絕時傳遞給拒絕回調的值。

2.2.2 3種狀態

  • 等待態(Pending)
  • 執行態(Fulfilled)
  • 拒絕態(Rejected)

enter description here

針對每種狀態的規範 等待態(Pending) 處於等待態時,promise 需知足如下條件:

  • 能夠遷移至執行態或拒絕態

執行態(Fulfilled)

處於執行態時,promise 需知足如下條件:

  • 不能遷移至其餘任何狀態
  • 必須擁有一個不可變的終值

拒絕態(Rejected)

處於拒絕態時,promise 需知足如下條件:

  • 不能遷移至其餘任何狀態
  • 必須擁有一個不可變的據因

2.2.3 2種事件

針對3種狀態,只有以下兩種轉換方向:

  • pending –> fulfilled
  • pendeing –> rejected

在狀態轉換的時候,就會觸發事件。

若是是pending –> fulfiied,就會觸發onFulFilled事件 若是是pendeing –> rejected,就會觸發onRejected事件

2.2.4 1個對象

就是指promise對象

2.3 promise的基本用法

2.3.1 基本用法

let p = new Promise(function (resolve,reject) {
            reject("no");
        })
        console.log('p :', p);
複製代碼

回調函數中的兩個參數,其做用就是用於轉換狀態:

resolve,將狀態從pending –> fullFilled reject,將狀態從pending –> rejected

2.3.2 then 方法

在狀態轉換的時候,就會觸發事件

若是是pending –> fulfiied,就會觸發onFulFilled事件

若是是pendeing –> rejected,就會觸發onRejected事件

針對事件的註冊,Promise對象提供了then方法,以下:

enter description here

2.3.3promise典型定義

2.3.3.1 案例1:讀取文件操做

const fs = require("fs");

let p = new Promise(function (resolve,reject) {
    fs.readFile("03-js基礎/a.txt","utf8",(err,date)=>{
        if(err){
            reject(err);
        }else{
            resolve(date);
        }
    });
  });
  
  p.then(result=>{
      console.log('result :', result);
  }).catch(err=>{
      console.log('err :', err);
  });
複製代碼

2.3.3.2 案例2:根據隨機數返回結果

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        let num = Math.random();
        if(num>0.5){
            resolve("success");
        }else{
            reject("fail");
        }
    },1000);
});

p.then(result=>{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
複製代碼

2.3.3.3 讀取文件封裝

const fs = require("fs");

function readFile(file){
    return new Promise((resolve,reject)=>{
        fs.readFile("file","utf8",(err,date)=>{
            if(err){
                reject(err);
            }else{
                resolve(date);
            }
        });
    });
}

readFile("a.txt").then(result=>{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
複製代碼

2.3.4 all和race方法

all:全部,所有執行,而且知足要求 race:競賽,誰跑的快,執行誰的(不分紅功與失敗)

all和race都是Promise構造器對象的靜態方法。直接使用Promise調用,以下:

  • Promise.all()
  • Promise.reace()
    • 返回值都是promise對象。

當有多個異步操做的時候,常常會有以下兩種需求:(有點相似於運算符中的 邏輯與邏輯或

  1. 確保全部的異步操做完成以後,才進行某個操做,只要有一個失敗,就不進行

  2. 只要有一個異步操做文章,就裏面執行某個操做。

all使用以下

enter description here

若有錯誤,以下

enter description here

注意:

all 方法必須全部的異步徹底正確,纔會返回true,當其中一個出錯的時候,返回false,而且會將第一個出錯的錯誤信息拋出

reac的用法

enter description here

注意:

reac 方法,就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])裏面哪一個結果得到的快,就返回那個結果,無論結果自己是成功狀態仍是失敗狀態。

2.4 使用第三方的Promise庫

針對第三方的promise庫,有兩個知名的庫:

  • bluebird
  • q.js

以bluebird爲例,在服務端演示其用法

第一步,安裝

enter description here

第二步,使用

enter description here

2.5 手寫最完整版的promise原理

本人在github中 逐步的封裝了基礎版promise,升級版promise,完整版的promise,能夠進入Github中更有層次的學習原理,

Github地址:github.com/quyuandong/…

promise的原理

3. 解決方案之generator 與 co

3.1 Generator的出現

ES6 增長了一項新的內容:生成器(Generator)。生成器是一種能夠從中退出並在以後從新進入的函數。生成器的環境(綁定的變量)會在每次執行後被保存,下次進入時可繼續使用

3.2 Generator的使用

生成器的定義相似於普通的函數,只是要加一個*號,好比:function * g() { // 定義一個空生成器}yield關鍵字是生成器函數中的亮點(只能在Generator函數中才能使用,普通函數中不可以使用),其字面意思爲「產出」,每次程序執行到yield的時候,都會「產出」一個結果。

其實Generatoryield 兩個詞用的已經很是形象了,Generator就相似於一個工廠,每當消費者須要某種東西的時候,yield 就負責去生產,生產完了返回給消費者。

示例:

enter description here

3.3 Generator的執行方式

enter description here

3.4 generator和Promise、co配合使用

co庫地址:github.com/tj/co

$ npm install co

enter description here

4. 解決方案之async 與 await

async/await是對Promise的優化: async/await是基於Promise的,是進一步的一種優化,不過在寫代碼時,Promise自己的API出現得不多,很接近同步代碼的寫法;

4.1 async關鍵字

  • 1)代表程序裏面可能有異步過程:
    • 裏面能夠有await關鍵字;也能夠沒有(沒有表示所有同步);
  • 2)非阻塞:
    • async函數裏面若是有異步過程會等待,可是async函數自己會立刻返回,不會阻塞當前線程,async函數內部由await關鍵字修飾的異步過程,工做在相應的協程上,會阻塞等待異步任務的完成再返回;
  • 3)async函數返回類型爲Promise對象:
  • 4)無等待
    • 在沒有await的狀況下執行async函數,它會當即執行,返回一個Promise對象,

4.2 await關鍵字

  • 1)await只能在async函數內部使用:不能放在普通函數裏面,不然會報錯;

  • 2)await關鍵字後面跟Promise對象:在Pending狀態時,相應的協程會交出控制權,進入等待狀態,這是協程的本質;

  • 3)await是async wait的意思: wait的是resolve(data)的消息,並把數據data返回,

  • 4)await後面也能夠跟同步代碼: 不過系統會自動將其轉化成一個Promsie對象,

4.3 簡單的使用案例:

enter description here

源碼

function timeout(ms) {
    return new Promise((resolve, reject) => {
      setTimeout(resolve, ms, "finish");
    });
  }

  //異步代碼
  async function asyncTimeSys(){
      await timeout(1000);
  }

  //調用方法,接收返回值
  asyncTimeSys().then((value)=>{
      console.log(value);
  });
複製代碼
相關文章
相關標籤/搜索