async await 了解

问题引出:php

思考(案例来自stackoverflow):html

function foo(){ var result; $ajax({ url:'...', success:function(response){ result=response; //return response;//tried this one as well } }); return result; } var result=foo();

初学异步的时候,这里是很容易错的地方,你想要获取从服务器端返回的数据,结果却一直undefined。ajax

!!!气死我了编程


 

在弄清楚此概念以前,先了解 JS 的异步机制:segmentfault

参考连接:http://www.javashuo.com/article/p-xackczmh-cr.html数组

http://www.javashuo.com/article/p-xqrpyxku-dd.htmlpromise

http://www.javashuo.com/article/p-ffewwzss-bq.html浏览器

http://www.ruanyifeng.com/blog/2015/05/async.html服务器

首先先了解什么是同步和异步多线程

同步:

 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;就像上面的图中同样,线性执行

异步:

若是函数是异步的,这个函数在被调用的时候,会立刻返回一个结果,可是这个结果可能不是预期的哦。(这是由于这个函数尚未获得最终的结果,可是又不能让人家一直等着,因此就先返回一个结果,致使不阻塞住)。等到这个函数终于知道结果了,若是有调用他的,他才告诉人家正确的结果。

下面以AJAX请求为例,来看一下同步和异步的区别:

  • 同步ajax

主线程:“你好,AJAX线程。请你帮我发个HTTP请求吧,我把请求地址和参数都给你了。”

AJAX线程:“......”

主线程::“喂,AJAX线程,你怎么不说话?”

AJAX线程:“......”

主线程::“喂!喂喂喂!”

AJAX线程:“......”

(一炷香的时间后)

主线程::“喂!求你说句话吧!”

AJAX线程:“主线程,很差意思,我在工做的时候不能说话。你的请求已经发完了,拿到响应数据了,给你。”

  • 异步ajax

主线程:“你好,AJAX线程。请你帮我发个HTTP请求吧,我把请求地址和参数都给你了。”

AJAX线程:“好的,主线程。我立刻去发,但可能要花点儿时间呢,你能够先去忙别的。”

主线程::“谢谢,你拿到响应后告诉我一声啊。”

(接着,主线程作其余事情去了。一顿饭的时间后,它收到了响应到达的通知。)

 单线程语多线程、JS 单线程:

在上面介绍异步的过程当中就可能会纳闷:既然JavaScript是单线程,怎么还存在异步,那些耗时操做到底交给谁去执行了?

JavaScript其实就是一门语言,说是单线程仍是多线程得结合具体运行环境。JS的运行一般是在浏览器中进行的,具体由JS引擎去解析和运行。下面咱们来具体了解一下浏览器。

浏览器:

目前最为流行的浏览器为:Chrome,IE,Safari,FireFox,Opera。浏览器的内核是多线程的。

一个浏览器一般由如下几个常驻的线程:

  • 渲染引擎线程:顾名思义,该线程负责页面的渲染
  • JS引擎线程:负责JS的解析和执行
  • 定时触发器线程:处理定时事件,好比setTimeout, setInterval
  • 事件触发线程:处理DOM事件
  • 异步http请求线程:处理http请求

须要注意的是,渲染线程和JS引擎线程是不能同时进行的。渲染线程在执行任务的时候,JS引擎线程会被挂起。由于JS能够操做DOM,若在渲染中JS处理了DOM,浏览器可能就不知所措了。

JS引擎:

一般讲到浏览器的时候,咱们会说到两个引擎:渲染引擎和JS引擎。渲染引擎就是如何渲染页面,Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trident引擎,FireFox用的是Gecko引擎。不一样的引擎对同一个样式的实现不一致,就致使了常常被人诟病的浏览器样式兼容性问题。这里咱们不作具体讨论。

JS引擎能够说是JS虚拟机,负责JS代码的解析和执行。一般包括如下几个步骤:

  • 词法分析:将源代码分解为有意义的分词
  • 语法分析:用语法分析器将分词解析成语法树
  • 代码生成:生成机器能运行的代码
  • 代码执行

不一样浏览器的JS引擎也各不相同,Chrome用的是V8,FireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。

之因此说JavaScript是单线程,就是由于浏览器在运行时只开启了一个JS引擎线程来解析和执行JS。那为何只有一个引擎呢?若是同时有两个线程去操做DOM,浏览器是否是又要不知所措了。

因此,虽然JavaScript是单线程的,但是浏览器内部不是单线程的。一些I/O操做、定时器的计时和事件监听(click, keydown...)等都是由浏览器提供的其余线程来完成的。

咱们常说“JavaScript是单线程的”。所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。

可是实际上还存在其余的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎以内,也可能存在于JS引擎以外,在此咱们不作区分。不妨叫它们工做线程。

正是因为JavaScript是单线程的,而异步容易实现非阻塞,因此在JavaScript中对于耗时的操做或者时间不肯定的操做,使用异步就成了必然的选择。

 
 
解决办法:
1. 经过回调函数解决
function foo(callback){//定义函数的时候将另外一个函数(回调函数)做为参数传入定义的函数中。 $ajax({ //... success:callback//异步操做执行完毕后,再执行该回调函数,确保回调在异步操做以后执行。 }); } function myCallback(result){ //... } foo(myCallback);
 
上面一段代码解释: 咱们定义了两个函数 myCallback 和 foo。
  foo 函数里面呢,是有异步操做的(ajax),按照正常状况,他会返回一个不是真正结果的值,那咱们怎么样才能获得真正的结果呢?就是当这个函数执行完的时候,调用 myCallback(这个函数是经过参数传进来的),获得这个真正的结果,就解决了这个问题。
优势:比较容易理解;
缺点:1.高耦合,维护困难,回调地狱; 2.每一个任务只能指定一个回调函数; 3.若是几个异步操做之间并无顺序之分,一样也要等待上一个操做执行结束再进行下一个操做。
 
2. Promise
 

先看上面这个函数是什么意思: ajax 函数执行,而后是两个 then 方法和一个 catch 方法 =》 ajax 里面是啥呢? 是返回了一个 Promise 的东西 =》 Promise 里面是啥呢? 是一系列函数执行,我也不知道这是执行的啥,反正就是在执行。

那就看看这个 Promise 是个什么东西?烦死了,弄的稀奇古怪的。

Promise表明了一个异步操做,能够将异步对象和回调函数脱离开来,经过.then方法在这个异步操做上绑定回调函数,Promise可让咱们经过链式调用的方法去解决回调嵌套的问题。先捋一下, 应该就是 Promise 里面的是一个异步操做,then 函数是在他执行完以后才回去挨个执行的,应该是这个意思吧,和上面那种比就是换了个写法嘛。

promise对象存在三种状态:
1)Fulfilled:成功状态
2)Rejected:失败状态
3)Pending:既不是成功也不是失败状态,能够理解为进行中状态

promise对象的两个重要方法:resolve/reject
1)resolve方法可使Promise对象的状态改变为成功,同时传递一个参数用于后续成功后的操做。
2)reject方法能够将Promise对象的状态改变为失败,同时将错误信息传递到后续错误处理的操做。

.then可使用链式调用,缘由在于:每一次执行该方法时总会返回一个Promise对象(Promise 对象的意义就是告诉成功仍是失败吧)。
另外,在then的函数当中的返回值,能够做为后续操做的参数(例如:.then(return a).then(console.log(a+b))),这不就是线性执行了嘛!!!

 那么问题来了,若是上面代码异步操做抛出错误,会怎么样?会调用catch方法指定的回调函数,处理这个错误,并且then方法指定的回调函数,若是运行中抛出错误,也会被catch捕获。Promise对象的错误具备“冒泡”性质,会一直向后传递,直到被捕获为止,也就是说,错误老是会被下一个catch语句捕获。
 

理解Promise用法的关键点:
1.then方法是Promise实例的方法,即Promise.prototype上的,它的做用是为Promise实例添加状态改变时的回调函数,这个方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
2.链式中的第二个then开始,它们的resolve中的参数,是前一个then中resolve的return语句的返回值。
3.关于执行顺序:Promise在实例化的时候就会执行,也就是若是Promise的实例化语句中函数console.log输出语句,它会比then中的先执行。Promise.all中传入的Promise对象的数组(假设为p一、p2),即便p2的运行速度比p1快,Promise.all方法仍然会按照数组中的顺序将结果返回。
理解了上面这些方便写原生的Promise,利用观察者模式。后面补充。

Promise的缺点:
1.当处于未完成状态时,没法肯定目前处于哪一阶段。
2.若是不设置回调函数,Promise内部的错误不会反映到外部。
3.没法取消Promise,一旦新建它就会当即执行,没法中途取消。

 

3.async/await:

不少人说async/await是异步编程的终极解决方案、
JavaScript 的 async/await 实现,离不开 Promise。

 

看上面这段代码: 有一个 delay 函数,里面有Promise关键字(代表是异步操做,你们让让,我先执行)。 在看 getAllBooks 函数, 它里面有 await 这个关键字(意如其名,你们等等,等下面这个执行完了才能执行别的)

上面的 delay() 没有申明为 async。实际上,delay() 自己就是返回的 Promise 对象,加不加 async 结果都同样。

只要在函数名以前加上async关键字,就代表这个函数内部有异步操做。这个异步操做返回一个Promise对象,前面用await关键字注明。函数执行的时候,一旦遇到await,就会先执行await后面的表达式中的内容(异步),再也不执行函数体后面的语句。等到异步操做执行完毕后,再自动返回到函数体内,继续执行函数体后面的语句。

  async:定义异步函数

1)自动把函数转换为Promise
2)当调用异步函数时,函数返回值会被resolve处理
3)异步函数内部可使用await

await:暂停异步函数的执行
1)当使用在Promise前面时,await等待Promise完成,并返回Promise的结果
2)await只能和Promise一块儿使用,不能和callback一块儿使用
3)await只能用在async函数中

async/await并不会取代promise,由于async/await底层依然使用promise。

每次遇到 await 关键字时,Promise 都会停下在,await 把异步变成了同步。

相关文章
相关标签/搜索