關於js回調和promise,async/await的理解

關於js,promise,async/await的理解

1、js

const a = function() {
  setTimeout(function() {
    console.log(1)
  }, 2000)
}
a()
console.log(2)
//執行結果:
2
1
複製代碼

setTimeout模擬異步回調函數,假設一個回調函數須要2秒猜返回結果。能夠看到a函數調用時,並無立馬打印出結果就執行下一行打印語句了。
js是單線程的,是從上至下執行語句的,爲了避免阻塞語句執行,就有回調機制。回調至關於註冊了一個事件池,回調函數註冊到這個池子裏,在這個池子裏去執行回調函數本身的邏輯,有返回結果後才傳回給主線程。 下面這個node鏈接數據庫,返回查詢結果undefined,也是這個問題。javascript

var mysql = require('mysql');
const mysql = function() {
    console.log('鏈接的database是', database)
    const url = {
        host     : 'localhost',
        user     : 'root',
        password : '123456',
        database : 'test'
    }
    var connection = mysql.createConnection(url);
       
    connection.connect();
    var mysqlQuery = function(callback) {
        var  sql = 'SELECT * FROM test1'
        connection.query(sql,function(err,result){
            if(err){console.log(err)}
            callback(result)
        })  
    }
    const result = mysqlQuery(function(data) {
        return data
    })
    console.log(result)
    console.log(2)
}
mysql()
// 在console.log(result)時會獲取不到結果
複製代碼

2、promise

promise 簡單理解就promise狀態變化的回調函數放到then和catch裏,(也能夠都放在then裏面)約定好成功就執行then裏面的函數,失敗就執行catch裏面的函數。就能夠按咱們但願的去執行哪一個回調,很容易控制執行的順序。
詳細說法promise構造函數接受兩個參數,分別是resolve和reject函數,resolve函數的做用是把promise對象的狀態從pending變成resolved(未完成到完成),reject函數做用是把promise對象的狀態從pending變成reject(未完成到失敗)。狀態改變後的回調函數分別定義在then裏面。java

//實例化promise對象,至於這個promise對象的構造函數什麼樣不用管,javascript引擎提供了
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
//Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then(function(value) {
  // success
}, function(error) {
  // failure
})
複製代碼

promise實例建立後,狀態改變後的回調函數要將在當前腳本全部同步任務執行完纔會執行。node

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved`
複製代碼

上面代碼中,Promise 新建後當即執行,因此首先輸出的是Promise。而後,then方法指定的回調函數,將在當前腳本全部同步任務執行完纔會執行,因此resolved最後輸出。mysql

3、ansyc/await

Async

先從async關鍵字提及,它被放置在一個函數前面。就像下面這樣:sql

async function f() {
    return 1
} 
複製代碼

函數前面的async一詞意味着一個簡單的事情:這個函數老是返回一個promise,若是代碼中有return <非promise>語句,JavaScript會自動把返回的這個value值包裝成promise的resolved值。因此調用這個函數時後面.then(reslove)獲取return的值數據庫

async function f() {
    return 1
}
f().then(alert) // 1
複製代碼

能夠顯式的返回一個promise,這個將會是一樣的結果:json

async function f() {
    return Promise.resolve(1)
}
f().then(alert) // 1
複製代碼
Await
// 只能在async函數內部使用
let value = await promise
複製代碼

關鍵詞await可讓JavaScript進行等待,直到一個promise執行並返回它的結果,JavaScript纔會繼續往下執行。
例子:segmentfault

async function f() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('done!'), 1000)
    })
    let result = await promise // 直到promise返回一個resolve值(*)
    alert(result) // 'done!' 
}
f()

複製代碼

函數執行到(*)行會‘暫停’,當promise處理完成後從新恢復運行,上面await會把promise執行的結果返回,賦值給了result, resolve的值成了最終的result,因此上面的代碼會在1s後輸出'done!'。
await是一個更優雅的獲得promise值的語句,它比promise更加容易閱讀和書寫。
也就是把promise的.then替換爲await數組

  • await不能工做在頂級做用域
let response = await fetch('/article/promise-chaining/user.json')
let user = await response.json()
因此咱們須要將await代碼包裹在一個async函數中,就像上面的例子同樣。
複製代碼
  • 一個class方法一樣可以使用async,只須要將async放在它以前就能夠 就像這樣:
async wait () {
       return await Promise.resolve(1)
   }
}
new Waiter().wait().then(alert) // 1
這裏的意思是同樣的:它確保了返回值是一個promise,支持await

複製代碼

錯誤處理

若是一個promise正常resolve,那麼await返回這個結果,可是在reject的狀況下會拋出一個錯誤,就好像在那一行有一個throw語句同樣。promise

async function f() {
    await Promise.reject(new Error('whoops!'))
}
複製代碼

和下面同樣

async function f() {
    throw new Error('Whoops!')
}   
複製代碼

在真實的使用場景中,promise在reject拋出錯誤以前可能須要一段時間,因此await將會等待,而後才拋出一個錯誤。 咱們能夠使用try-catch語句捕獲錯誤,就像在正常拋出中處理異常同樣:

async function f() {
    try {
        let response = await fetch('http://no-such-url')
    } catch (err) {
        alet(err) // TypeError: failed to fetch
    }
}
f()
複製代碼

若是咱們不使用try-catch,而後async函數f()的調用產生的promise變成reject狀態的話,咱們能夠添加.catch去處理它:

async function f() {
    let response = await fetch('http://no-such-url')
}
// f()變成了一個rejected的promise
f().catch(alert) // TypeError: failed to fetch
複製代碼
async/await可以與Promise.all友好的協做
當咱們須要等待多個promise時,咱們能夠將他們包裝在Promise.all中而後使用await:

// 直到數組所有返回結果
let results = await Promise.all([
   fetch(url1),
   fetch(url2),
   ...
])
若是發生了一個錯誤,它就像普通狀況同樣:從一個失敗狀態的promise到Promise.all,而後變成了一個咱們可以使用try-cathc去捕獲的異常。
複製代碼

參考文章async/await

4、將js中的異步回調例子修改

var mysql = require('mysql');
const mysql = function() {
    console.log('鏈接的database是', database)
    const url = {
        host     : 'localhost',
        user     : 'root',
        password : '123456',
        database : 'test'
    }
    var connection = mysql.createConnection(url);
       
    connection.connect();
    var mysqlQuery = new Promise((resolve, reject) => {
        var  sql = 'SELECT * FROM test1'
        connection.query(sql,function(err,result){
            if(err){console.log(err)}
            resolve(result)
        })
    }) 
    const result = await mysqlQuery(function(data) {
        return data
    })
    console.log(result)
    console.log(2)
}
mysql()
// 數據庫查詢結果
//2
複製代碼

相關文章
相關標籤/搜索