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 次浏览

开启你的 职业生涯

通过完成课程获得认证

立即开始
广告