傳統的非同步解決方案採用回調函數和事件監聽的方式,而這裡主要記錄兩種非同步編程的新方案: ES6的新語法Promise ES2017引入的async函數 Generator函數(略) Promise的含義 是非同步變成的一種解決方案,屬於ES6的語法。 簡單的說,promise就是一個容器,裡面包含著一個 ...
傳統的非同步解決方案採用回調函數和事件監聽的方式,而這裡主要記錄兩種非同步編程的新方案:
- ES6的新語法Promise
- ES2017引入的async函數
- Generator函數(略)
Promise的含義
是非同步變成的一種解決方案,屬於ES6的語法。
簡單的說,promise就是一個容器,裡面包含著一個未來才會結束的事件(通常是一個非同步操作)的結果。
比起傳統的非同步解決方案(回調函數和事件),promise更合理更強大,把非同步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。
Promise的基本用法
ES6規定,Promise是一個構造函數,接受一個函數作為參數,該函數有兩個參數分別是resolve和reject:/** * resolve 非同步操作成功時調用的方法,並將非同步操作的結果作為參數傳遞出去 * reject 非同步操作失敗時調用的方法,並將報錯傳遞出去 */ var promise = new Promise(function(resolve, reject) { var isSuccess = true // 非同步操作是否成功 if (isSuccess) { resolve(data) } else { reject(error) } })
Promise實例生成以後,可以用then方法,傳入兩個函數,分別指定resolve狀態和reject狀態的回調函數(第二個函數可選):
promise.then(function() { // 非同步操作成功的處理,resolve狀態 }, function() { // 非同步操作失敗的處理,reject狀態 })
一個Promise對象的簡單例子:
var timeout = function(ms) { var data = { list: Array(0), msg: 'success', status: 200 } return new Promise(function(resolve, reject) { setTimeout(resolve, ms, data) }) } timeout(1000).then(function(data) { console.log(data) }, function(error) { console.log(error) })
非同步載入圖片的例子:
function loadImageAsync(src) { return new Promise(function(resolve, reject) { var image = new Image() image.src = src image.onload = function() { resolve(image) } image.onerror = function() { reject(new Error(`載入圖片失敗,url:${url}`)) } }) } var url = 'http://n.sinaimg.cn/ent/transform/250/w160h90/20190226/jjhJ-htptaqe5318645.jpg' loadImageAsync(url).then((image) => { document.body.append(image) }, (err) => { console.log(err) })
async函數
在普通函數前面加 async,就意味著函數內包含了非同步操作。async函數返回一個Promise對象,可以使用then方法添加回調函數。 在執行的時候,一旦遇到 await 命令就會先返回,等到非同步操作完畢,在接著執行函數體內後面的語句。簡單的例子,指定多少毫秒後輸出一個值:
function timeout(ms) { return new Promise(function(resolve, reject) { setTimeout(() => { resolve() }, ms) }) } async function asyncPrint(ms) { await timeout(ms) console.log(`過去了${ms}毫秒,輸出此語句`) } asyncPrint(1000)語法註意點: 1. async 函數返回 一個Promise 對象。async 函數內部return語句返回的值,會成為then回調函數的參數。
async function f() { return 'hello' }
f().then((data) => { console.log(data) // ‘hello’ })
2. async函數內部拋出錯誤,會導致返回的 Promise 對象編程reject狀態,拋出的錯誤對象會被catch回調函數接收到。
async function f() { throw new Error('出錯了') } f().then((data) => { console.log('resolve data:', data) }).catch((err) => { console.log('reject error:', err) })或者簡寫成
f().then( data => console.log(data), err => console.log(err) )
3. 防止出錯的方法,也是將其放在try...catch代碼塊之中。
async function main() { try { const val1 = await firstStep(); const val2 = await secondStep(val1); const val3 = await thirdStep(val1, val2); console.log('Final: ', val3); } catch (err) { console.error(err); } }