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 的更好版本,並使其程式碼更簡潔。

更新於: 2019年9月4日

851 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

立即開始
廣告