由於javascript是單線程的執行模型,因此為了提高效率就有了非同步編程,單線程在程式執行時,所走的程式路徑按照連續順序排下來,前面的必須處理好,後面的才會執行。 但是我們也需要類似多線程機制的這種執行方式,我們需要非同步執行編程,非同步執行編程會使得多個任務併發執行。 非同步編程可以實現多任務併發執行 ...
由於javascript是單線程的執行模型,因此為了提高效率就有了非同步編程,單線程在程式執行時,所走的程式路徑按照連續順序排下來,前面的必須處理好,後面的才會執行。 但是我們也需要類似多線程機制的這種執行方式,我們需要非同步執行編程,非同步執行編程會使得多個任務併發執行。 非同步編程可以實現多任務併發執行,指同一時刻內多任務同時進行,邊煮飯,邊燒水,可以同時進行,進而提高效率。
1.回調函數
回調函數,就是把任務的第二段單獨寫在一個函數裡面,等到重新執行這個任務的時候,就直接調用這個函數。
const fs = require('fs') fs.readFile('/etc/passwd', (err, data) => { if (err) { console.error(err) return } console.log(data.toString()) })
回調函數最大的問題是容易形成回調地獄,即多個回調函數嵌套,降低代碼可讀性,增加邏輯的複雜性,容易出錯。
fs.readFile(file1, function (err, data) { fs.readFile(file2, function (err, data) { // }) })
2.promise
為解決回調函數的不足,就有了Promise。
const fs = require('fs') const readFileWithPromise = file => { return new Promise((resolve, reject) => { fs.readFile(file, (err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) } readFileWithPromise('/etc/passwd') .then(data => { console.log(data.toString()) return readFileWithPromise('/etc/profile') }) .then(data => { console.log(data.toString()) }) .catch(err => { console.log(err) })
promise 實際上是利用編程技巧將回調函數的橫向載入,改成縱向載入,達到鏈式調用的效果,避免回調地獄。最大問題是代碼冗餘,原來的任務被 promise 包裝了一下,優點是減少代碼嵌套,代碼邏輯清晰。
3.async、await
為瞭解決 promise 的問題,async、await 在 ES7 中被提了出來
const fs = require('fs') async function readFile() { try { var f1 = await readFileWithPromise('/etc/passwd') console.log(f1.toString()) var f2 = await readFileWithPromise('/etc/profile') console.log(f2.toString()) } catch (err) { console.log(err) } }
特點:
1.非同步async函數的調用,跟普通的函數使用方式一樣;
2.async的用法,它作為一個關鍵字放到函數前面,這樣普通函數就變成了非同步函數;
3.非同步async函數返回一個promise對象;
4.async函數配合await使用可以阻塞代碼往下執行,是非同步方法。
優點:
1.多個參數傳遞:promise使用then函數只能傳遞一個參數,雖然可以通過包裝成對象來傳遞多個參數,但是會導致傳遞冗餘信息,頻繁的解析又重新組合比較麻煩;而利用async和await可以沒有這個限制,可以當做普通變數的局部變數來處理,也沒有冗餘工作;
2.同步和非同步一起編寫:使用promise的時候最好將同步代碼和非同步代碼放在不同的then節點中,這樣結構更加清晰;async和await整個書寫習慣都是同步的,不需要糾結同步和非同步的區別,當然,非同步過程需要包裝成一個promise對象放在await關鍵字後面;
3. 對promise的優化:async和await是基於promise的,是進一步的一種優化。
使用場景:
async和await主要用來處理非同步的操作,執行第一步,將執行第一步的結果返回給第二步使用,在ajax中先拿到一個介面的返回數據,後使用第一部返回的數據執行第二步操作的介面調用,達到非同步操作。