Promise、Callbacks 和 Async/Await
首先,我們必須理解兩個主要概念
- 同步程式設計
- 非同步程式設計
同步程式設計
它等待每個語句完成執行,然後才執行下一個語句。
如果語句之間沒有依賴關係,但仍然需要等待執行(因為它們排隊),這種方法可能會降低應用程式的處理速度。
非同步程式設計
它不會等待當前語句完成執行,然後才執行下一個語句。例如,在 JavaScript 中呼叫 Web 服務和執行檔案複製。
呼叫 Web 服務可能需要一些時間才能返回結果,在此期間,我們可以完成其他操作。
一旦伺服器提供結果,我們就可以處理它,而無需等待。
我們的三種方法 1. Callbacks 2. Promises 3. Async/Await 處理非同步程式設計。
Callbacks
const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); }; getArticles();
在這裡,我們只是建立了一個文章陣列,並在 1 秒後將其列印到控制檯。
使用 setTimeout 函式和 1 秒的時間只是為了展示類似於伺服器的行為。
現在,如果我們透過另一個函式向上述列表中新增一篇新文章會怎樣?
function createArticle(article){ setTimeout(()=>{ articles.push(article); },2000); }
如果我們現在用新文章呼叫 createArticle,然後呼叫 getArticle,我們應該得到三篇文章,但我們只得到前兩篇文章。
const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); }; function createArticle(article){ setTimeout(()=>{ articles.push(article); },2000); } createArticle({title:'Third article'}); getArticles(); //console output "First article Second article "
為什麼會這樣?
因為 createArticle 的執行有 2 秒的超時,在此期間,getArticle 完成了執行。
示例
const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); }; function createArticle(article, callback){ setTimeout(()=>{ articles.push(article); callback(); },2000); } createArticle({title:'Third article'},getArticles); //console output "First article Second article Third article "
我們使用回撥將 getArticle 的呼叫巢狀在 createArticle 中。
請注意將 getArticles 作為引數傳遞給 createArticle 函式。但是,這樣巢狀回撥會變得很複雜。
Promises
使用 promises,我們不需要傳遞迴調函式。Promises 有兩個引數 resolve 和 reject。*如果函式成功執行,我們可以呼叫 resolve(),否則我們呼叫 reject()*
const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); }; function createArticle(article){ return new Promise((resolve,reject)=>{ articles.push(article); let isError=false; if(!isError){ resolve(); } else { reject(); } }); } createArticle({title:'Third article'}) .then(getArticles()); //console output "First article Second article Third article " handling error with promises: const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); }; function createArticle(article){ return new Promise((resolve,reject)=>{ articles.push(article); let isError=true; if(!isError){ resolve(); }else{ reject('Something went wrong'); } }); } createArticle({title:'Third article'}) .then(getArticles()) .catch(error=>console.log(error)); //console output "Something went wrong"
我們從 createArticle 呼叫了 reject 並捕獲了錯誤。
Promise All
const promise1=Promise.resolve('Hello'); const promise2=100; const promise3=new Promise((resolve,reject)=>{ setTimeout(resolve,2000,'test'); }); Promise.all([promise1,promise2,promise3]) .then((values)=>console.log(values)); //console output ["Hello", 100, "test"]
我們可以將 promises 組合到一個數組中,然後使用實際的 then 語句,而不是在每個 promise 後巢狀 then 語句。
我們可以將 fetch api 與 jsonplaceholder 一起使用。
const promise0=fetch('https://jsonplaceholder.typicode.com/users').then(res=>res.json()); const promise1=Promise.resolve('Hello'); const promise2=100; const promise3=new Promise((resolve,reject)=>{ setTimeout(resolve,2000,'test'); }); Promise.all([promise0,promise1,promise2,promise3]) .then((values)=>console.log(values));
Async / Await
要在語句上使用 await,該函式應標記為 async。
<!DOCTYPE html> <html> <head> <title>Async/Await Example</title> </head> <body> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> const articles = [ {title:'First article'}, {title:'Second article'} ]; function getArticles(){ setTimeout(()=>{ let articleContent=''; articles.forEach((article,index)=>{ articleContent+=`${article.title}`+` `; }); console.log(articleContent); },1000); } function createArticle(article){ articles.push(article); } async function testAsync(){ await createArticle({title:'Third article'}); getArticles(); } testAsync(); //console output // First article Second article Third article </script> </body> </html>
testAsync 函式被標記為 async,我們使用 await 使 createArticle 函式首先完成。然後我們呼叫了 getArticles()。
使用 async / await 是 promises 的更好版本,並使其程式碼更簡潔。