Promise 、asyns、await介紹

回調地獄(callback hell)

回調地獄概念圖: javascript

回調地獄:在咱們須要對一個異步操做進行頻繁的調用的時候,且要保證一步操做的順序,可能會出現.java

var fs=require('fs');

/* 注意這裏的fs.readFile是一個異步任務,因此這裏他們輸出的順序並非 按照代碼的書寫順序,他們讀取文件的輸出順序,跟文件資源的大小還有其餘的元素有很大的關係 */

fs.readFile('./data/a.txt','utf8',function(err,data){
    if(err){
        /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
      throw err  
    }
    console.log(data);
});

fs.readFile('./data/b.txt','utf8',function(err,data){
    if(err){
       /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
      throw err  
    }
    console.log(data);
});


fs.readFile('./data/c.txt','utf8',function(err,data){
    if(err){
       /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
      throw err  
    }
    console.log(data);
});
複製代碼

經過回調嵌套的方式保證順序:ajax

var fs = require('fs');

/* 注意這裏的fs.readFile是一個異步任務,因此這裏他們輸出的順序並非 按照代碼的書寫順序,他們讀取文件的輸出順序,跟文件資源的大小還有其餘的元素有很大的關係 */

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
    if (err) {
        /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
        throw err
    }
    console.log(data);
    fs.readFile('./data/b.txt', 'utf8', function (err, data) {
        if (err) {
            /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
            throw err
        }
        console.log(data);

        fs.readFile('./data/c.txt', 'utf8', function (err, data) {
            if (err) {
                /* 拋出異常 1.阻止程序的執行 2.把錯誤的消息打印到控制檯 */
                throw err
            }
            console.log(data);
        });
    });
});

複製代碼

回調地獄的缺點: 1)代碼的可維護性很是差,不利於代碼的閱讀 2)層層嵌套,代碼複雜.promise

Promise簡介

爲了解決以上編碼方式帶來的問題(回調地獄嵌套),因此在ECMAScript 6 中新增了一個API:promise Promise的英文就是承諾 保證的意思bash

概念 : Promise是ES6中的新語法,Promise是一個構造函數,每一個new 出來的Promis實例對象都表明一個異步操做.異步

注意:使用promise並不會減小代碼量
複製代碼

Promise概念圖:

Promise語法介紹

簡單建立:async

//  Promise是構造函數
//  Promise.prototype上有.then() .catch .finally(),由於他綁定到了原型上,因此根據原型鏈的查找規則,他的實例對象也可使用這個方法
// Promise表示異步操做

// 下面的這個代碼表示建立了一個形式上的異步操做

// 經過new Promise()的時候,提供了一個function函數,在function函數中,能夠執行具體的異步操做
const p=new Promise(function(){
    // 在這個function中能夠執行具體的異步操做
    // 好比讀文件,或發送ajax
    // fs.readFile()
})
複製代碼

.then方法的使用:函數

const fs=require('fs');
// 在ES6中新增了一個API Promise
// Promise 是一個構造函數

// 建立promise容器
// 1.給別人一個承諾
// Promise容器一旦建立,就開始執行裏面的代碼,
// 承諾自己不是異步的,可是內部每每都是封裝一個異步任務
var p1=new Promise(function(resolve,rejected){
    fs.readFile('./data/a.txt','utf8',function(err,data){
        if(err){
            // 失敗了,承諾容器中的任務失敗了
            // console.log(err);
            // 把容器的Pending狀態改變爲Rejected
            //調用reject就至關於調用了then方法的第二個參數 
            rejected(err);
        }else{
            // 承諾容器中的任務成功了
            // console.log(data);
            // 把容器的Pending狀態改成Resolved
             // 也就是說這裏調用的resolve方法實際上就是then方法傳遞的function
            resolve(data);
        }
    });
});

// p1就是那個承諾
// 當p1成功了而後(then)作指定的操做
// then方法接收的function就是容器中的resolve
p1.then(function(data){
    console.log(data);
},function(err){
    console.log('讀取文件失敗了...',err);
})
複製代碼

封裝Promise版本的ReadFile:

const fs = require('fs');
 function pReadFile(filePath){
     return new Promise(function (resolve, rejected) {
        fs.readFile('./data/a.txt', 'utf8', function (err, data) {
            if (err) {
                rejected(err);
            } else {
                resolve(data);
            }
        });
    });
 }
 pReadFile('./data/a.txt')
    .then(function(data){
        console.log(data);
        return pReadFile('./data/b.txt');
    })
    .then(function(data){
        console.log(data);
        return pReadFile('./data/c.txt');
    })
    .then(function(data){
        console.log(data);
    })
    //能夠經過.catch方法,捕獲前面全部的.then方法發生的錯誤,幾種處理
    .catch(function(err){
        console.log(err.message)
    })
複製代碼

Promise代碼圖示:優化

asyns、await對Promise的優化

Generator

  • 說到async函數就不得不提起他在ES6中的表現,他其實就是Generator函數的一種語法糖
  • Generator能夠理解爲一個狀態機,他身上掛載了好多的狀態,
  • 執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator 函數除了狀態機,仍是一個遍歷器對象生成函數。返回的遍歷器對象,能夠依次遍歷 Generator 函數內部的每個狀態。

形式上,Generator 函數是一個普通函數,可是有兩個特徵。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield表達式,定義不一樣的內部狀態(yield在英語裏的意思就是「產出」) ES7 中的 async 和 await 能夠簡化 Promise 調用,提升 Promise 代碼的 閱讀性 和 理解性;ui

// 若是某個方法內部用到了await關鍵字,那麼這個方法必須被修飾爲異步async方法
// await只能用在被async修飾的方法中
async function test(){
    // 若是某個方法的返回值是Promise的實例對象,就能夠用await修飾Promise實例
    // await只能用在被async修飾的方法中
  const data=await getContentPath('./files/1.txt').catch(err=>err);
  if(data instanceof Error){
      console.log('文件讀取失敗')
  }else{
      console.log(data);
  }
  console.log(data);
  const data2=await getContentPath('./files/2.txt');
  console.log(data2);
  const data3=await getContentPath('./files/3.txt');
  console.log(data3);
}

// 這是異步方法,可是並非純粹的異步方法
// 在異步方法中,遇到第一個await以前,全部的代碼都是同步執行的
test();

複製代碼
注意:async和await通常是同步使用的,二者缺一不可,
複製代碼
相關文章
相關標籤/搜索