1. 程式人生 > 遊戲 >《巫師》重製版是開放世界RPG 與原作有很大不同

《巫師》重製版是開放世界RPG 與原作有很大不同

一、什麼是回撥函式?回撥函式有什麼缺點?如何解決回撥地獄問題?

  • 回撥函式概念

    • 回撥函式是一個作為變數傳遞給另一個函式的函式,它在主體函式執行完之後再執行
  • 回撥函式特點

    • 你定義的
    • 你沒有呼叫
    • 但是最終執行了
  • 回撥函式可能的缺點

    層層巢狀的非同步函式的操作叫做回撥地獄

    • 容易寫出回撥地獄
    • 不能使用 try catch 捕獲錯誤
    • 不能直接 return
  • 常見的回撥函式

    • DOM事件回撥函式
    • 定時器回撥函式
    • ajax請求回撥函式
    • 生命週期回撥函式
  • 如何解決回撥地獄

    • promise
    • async / await
    • generator

二、非同步程式設計的實現方式

1.回撥函式的方式

  • 使用回撥函式的方式有一個缺點是,多個回撥函式巢狀的時候會造成回撥函式地獄,上下兩層的回撥函式間的程式碼耦合度太高,不利於程式碼的可維護。

2.Promise的方式

  • 使用 Promise 的方式可以將巢狀的回撥函式作為鏈式呼叫。但是使用這種方法,有時會造成多個 then 的鏈式呼叫,可能會造成程式碼的語義不夠明確。

3.generator的方式

  • 它可以在函式的執行過程中,將函式的執行權轉移出去,在函式外部還可以將執行權轉移回來。當遇到非同步函式執行的時候,將函式執行權轉移出去,當非同步函式執行完畢時再將執行權給轉移回來。因此在 generator 內部對於非同步操作的方式,可以以同步的順序來書寫。使用這種方式需要考慮的問題是何時將函式的控制權轉移回來,因此需要有一個自動執行 generator 的機制,比如說 co 模組等方式來實現 generator 的自動執行。

4.async函式的方式

  • async 函式是 generator 和 promise 實現的一個自動執行的語法糖,它內部自帶執行器,當函式內部執行到一個 await 語句的時候,如果語句返回一個 promise 物件,那麼函式將會等待 promise 物件的狀態變為 resolve 後再繼續向下執行。因此可以將非同步邏輯,轉化為同步的順序來書寫,並且這個函式可以自動執行。

三、對Promise的理解

在構造 Promise 的時候,建構函式內部的程式碼是立即執行的

  • Promise本身是同步的立即執行函式,當在executor中執行 resolve() 或者 reject() 的時候, 此時是非同步操作,也就是說promise中函式體內部的非非同步操作正常順序執行,resolve() 和 reject() 非同步操作為promise例項物件的返回結果,這個返回結果後面的then或者catch需要用,所以then和catch要放到非同步任務中等待所有同步任務執行完畢之後再按順序(或者如果有定時器,需要遵循定時器的時間)執行。

  • Promise是非同步程式設計的一種解決方案,它是一個物件,可以獲取非同步操作的訊息,他的出現大大改善了非同步程式設計的困境,避免了地獄回撥,它比傳統的解決方案回撥函式和事件更合理和更強大。所謂Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個物件,從它可以獲取非同步操作的訊息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。

  • Promise 物件是非同步程式設計的一種解決方案,最早由社群提出。Promise 是一個建構函式,接收一個函式作為引數,返回一個 Promise 例項。一個 Promise 例項有三種狀態,分別是pending、resolved 和 rejected,分別代表了進行中、已成功和已失敗。例項的狀態只能由 pending 轉變 resolved 或者rejected 狀態,並且狀態一經改變,就凝固了,無法再被改變了。狀態的改變是通過 resolve() 和 reject() 函式來實現的,可以在非同步操作結束後呼叫這兩個函式改變 Promise 例項的狀態,它的原型上定義了一個 then 方法,使用這個 then 方法可以為兩個狀態的改變註冊回撥函式。這個回撥函式屬於微任務,會在本輪事件迴圈的末尾執行。

  • Promise的例項有三個狀態

    當把一件事情交給promise時,它的狀態就是Pending,任務完成了狀態就變成了Resolved、沒有完成失敗了就變成了Rejected

    • Pending(進行中)
    • Resolved(已完成)
    • Rejected(已拒絕)
  • Promise的例項有兩個過程

    一旦從進行狀態變成為其他狀態就永遠不能更改狀態了

    • pending -> fulfilled : Resolved(已完成)
    • pending -> rejected:Rejected(已拒絕)
  • Promise的特點

    • 物件的狀態不受外界影響。promise物件代表一個非同步操作,有三種狀態,pending(進行中)、fulfilled(已成功)、rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,這也是promise這個名字的由來——“承諾”。
    • 一旦狀態改變就不會再變,任何時候都可以得到這個結果。promise物件的狀態改變,只有兩種可能:從pending變為fulfilled,從pending變為rejected。這時就稱為resolved(已定型)。如果改變已經發生了,你再對promise物件添加回調函式,也會立即得到這個結果。這與事件(event)完全不同,事件的特點是:如果你錯過了它,再去監聽是得不到結果的。
  • Promise的缺點

    • 無法取消Promise,一旦新建它就會立即執行,無法中途取消
    • 如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部
    • 當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)

四、Promise解決了什麼問題

解決了地獄回撥的問題

五、Promise的基本用法

1.建立Promise物件

  • new Promise() 方法
  • promise.resolve() 方法
  • promise.reject() 方法

2.Promise方法

  • then() 方法
  • catch() 方法
  • all() 方法
  • race() 方法
  • finally() 方法

六、Promise.all和Promise.race的區別的使用場景

1.Promise.all()

  • Promise.all可以將多個Promise例項包裝成一個新的Promise例項。同時,成功和失敗的返回值是不同的,成功的時候返回的是一個結果陣列,而失敗的時候則返回最先被reject失敗狀態的值。Promise.all中傳入的是陣列,返回的也是是陣列,並且會將進行對映,傳入的promise物件返回的值是按照順序在陣列中排列的,但是注意的是他們執行的順序並不是按照順序的,除非可迭代物件為空。需要注意,Promise.all獲得的成功結果的數組裡面的資料順序和Promise.all接收到的陣列順序是一致的,這樣當遇到傳送多個請求並根據請求順序獲取和使用資料的場景,就可以使用Promise.all來解決。

2.Promise.race()

  • Promse.race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])裡面哪個結果獲得的快,就返回那個結果,不管結果本身是成功狀態還是失敗狀態。當要做一件事,超過多長時間就不做了,可以用這個方法來解決。

七、對async/await 的理解

  • async/await其實是Generator 的語法糖,它能實現的效果都能用then鏈來實現,它是為優化then鏈而開發出來的。從字面上來看,async是“非同步”的簡寫,await則為等待,所以很好理解async 用於申明一個 function 是非同步的,而 await 用於等待一個非同步方法執行完成。
  • async函式返回的是一個Promise 物件,如果在函式中 return 一個直接量,async 會把這個直接量通過 Promise.resolve() 封裝成 Promise 物件,async 函式返回的是一個 Promise 物件,所以在最外層不能用 await 獲取其返回值的情況下,當然應該用原來的方式:then() 鏈來處理這個 Promise 物件。

八、await 到底在等什麼

  • await後面必須是非同步函式, await是在等待一個非同步函式完成,而這個非同步函式返回值可能時promise物件,也可能是其他值,而await 等待的就是就是非同步函式的返回值。
    • 如果它等到的不是一個 Promise 物件,那 await 表示式的運算結果就是它等到的東西。
    • 如果它等到的是一個 Promise 物件,await 就忙起來了,它會阻塞在async函式之中且await後面的程式碼,等著 Promise 物件 resolve,然後得到 resolve 的值,作為 await 表示式的運算結果。

九、async/await的優勢

  • Promise 通過 then 鏈來解決多層回撥的問題,而 async/await 來進一步優化promise的 then() 方法的多層呼叫。
  • Promise傳遞中間值⾮常麻煩,⽽async/await⼏乎是同步的寫法,⾮常優雅 。
  • 錯誤處理友好,async/await可以⽤成熟的try/catch,Promise的錯誤捕獲⾮常冗餘。
  • 除錯友好,Promise的除錯很差,由於沒有程式碼塊,你不能在⼀個返回表示式的箭頭函式中設定斷點,如果你在⼀個.then程式碼塊中使⽤偵錯程式的步進(step-over)功能,偵錯程式並不會進⼊後續的.then程式碼塊,因為偵錯程式只能跟蹤同步程式碼的每⼀步。

十、async/await 如何捕獲異常

try...catch...

十一、setTimeout、Promise、Async/Await 的區別

1.setTimeout

  • 定時器是非同步任務,會將定時器中的程式碼放到非同步任務中,待頁面中所有同步任務執行完畢之後再執行非同步任務佇列。

    // 例如
    console.log('script start')
    setTimeout(function () {
        console.log('setTimeout')
    }, 0)
    console.log('script end')
    // 輸出順序:script start --> script end --> setTimeout
    

2.Promise

  • Promise本身是同步的立即執行函式, 當在executor中執行resolve或者reject的時候, 此時是非同步操作,會先執行promise中的同步任務,然後執行promise之外的同步操作(按照書寫程式碼的先後順序),而promise.then( )視為非同步任務的方法,會加入到任務佇列中,等待全部同步任務執行完畢再按順序執行非同步任務佇列中的任務,promise後面的定時器也是非同步函式,也要加入到非同步函式佇列中,即使定時器是0s,而且按照程式碼書寫先後順序,在任務佇列中會排到then後面。

  • new Promise():類似於同步。先微任務( Promise、async / await )再巨集任務( 定時器、Ajax、DOM事件 )

    // 例如
    console.log('script start')
    let promise1 = new Promise(function (resolve) {
        console.log('promise1')
        resolve()
        console.log('promise1 end')
    }).then(function () {
        console.log('promise2')
    })
    setTimeout(function () {
        console.log('setTimeout')
    }, 0)
    console.log('script end')
    // 輸出順序:script start --> promise1 --> promise1 end --> script end --> promise2 --> setTimeout
    

3.async / await

  • async函式為非同步函式,返回的也是promise物件,所以說async函式也是立即執行函式,他裡面的程式碼會按照順序相繼執行;但當有非同步任務,且非同步任務前面有await時,這時await若未等到非同步任務的結果,會阻礙async裡面且在await下面的程式碼(await後面緊跟著的非同步任務會正常執行),執行async函式下面的程式碼直至await等到結果之後再執行它下面在async函式中的程式碼。

    // 例如
    async function async1 () {
        console.log('async1 start')
        await async2()
        console.log('async1 end')
    }
    async function async2 () {
        console.log('async2')
    }
    console.log('script start')
    async1()
    console.log('script end')
    // 輸出順序:script start --> async1 start --> async2 --> script end --> async1 end
    

十二、併發與並行的區別

1.併發

  • 併發是巨集觀概念,在一段時間內通過任務間的切換完成了這些任務,這種情況就可以稱之為併發(指在同一時刻只能有一條指令執行,但多個程序指令被快速的輪換執行)。

2.並行

  • 並行是微觀概念,指在同一時刻,有多條指令在多個處理器上同時執行。同時完成多個任務的情況就可以稱之為並行。