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 的更好版本,并使其代码更简洁。