文章目录
  1. 1. 首先是第一个问题:
  2. 2. 然后是第二个问题:
  3. 3. 那就第三个问题啦
  4. 4. 最后第四个问题~~
  5. 5. 参考文章
  6. 6. 总结

之前一直搞不懂异步、Promise之类的是怎么回事,今天认真看了一下,总算把自己以前迷糊的点弄清楚了。下面是这篇文章主要讲的四个问题,若是你看到这里,可以看一下下面几个问题是否你也同样存在,如果存在,那这篇文章应该也适合你….那就拿走不谢啦…

之前的迷糊点:

  1. Js是单线程,那异步执行时,执行主逻辑代码,谁来执行异步代码??(呜呜…这个问题可不能笑我简单啊,这实在是困扰的我的最大的问题了)

  2. 这个异步好像是和事件啊信号啊之类的有关,那这是个什么关系啊?

  3. Promise究竟是怎么回事?发了那么多Ajax请求,总说那是promise的,可究竟是什么,里面机制是什么,怎么回事啊?还有那个CommonJs是个什么鬼?

  4. Promise是怎样实现的?在常用的Jquery中是怎样实现的?

下面是弄懂这些文章主要参考的文章,列出来,以后若是再迷糊了可以再看看,若是有哪位读者看到了这里或许也会需要。

首先是第一个问题:

Js确实是单线程的,但是所谓的单线程 是指在JS引擎中负责解释和执行JavaScript的代码的线程只有一个,即主线程。但是实际上还存在其他的线程。包括: 处理Ajax请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(在node.js中)等等,这些线程可能存在于JS引擎中,也可能存在于JS引擎之外,即 “工作线程”。(呜呜呜….之前我还天真的以为所有的只有一个线程,怎么可能嘛…….)

so easy. 第一个问题解决了。

然后是第二个问题:

首先先明确几个概念:

  1. 异步函数:如果在函数A返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那么这个函数就是异步函数,也可以叫异步过程的发起函数或者叫异步任务注册函数。主要形式是

    A(args,...,callbackFn)
    
  2. 异步过程:异步函数实际上很快就调用完成了。但是后面还有工作线程执行异步任务、通知主线程、主线程调用回调函数等很多步骤。我们把整个过程叫做异步过程。即:主线程发起一个异步请求,相应的工作线程接收请求并告知主线程已收到(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数)。

  3. 回调函数:回调函数与注册函数都是在主线程上调用的,其中注册函数发起异步请求,回调函数用来处理结果。

    那在这几个概念之后我们回到我的第二个问题:
    异步过程中,工作线程在异步操作完成后需要通知主线程。那么这个通知机制是怎样实现的呢?答案是利用>消息队列事件循环

    即 工作线程将消息放到消息队列,主线程通过事件循环过程去取消息。

实际上,主线程只会做一件事情,就是从消息队列里面取消息、执行消息,再取消息、再执行。当消息队列为空时,就会等待直到消息队列变成非空。而且主线程只有在将当前的消息执行完成后,才会去取下一个消息。这种机制就叫做事件循环机制,取一个消息并执行的过程叫做一次循环。

事件循环用代码表示大概是这样的:

while(true) {
    var message = queue.get();
    execute(message);
}

那么,消息队列中放的消息具体是什么东西?消息的具体结构当然跟具体的实现有关,但是为了简单起见,我们可以认为:

消息就是注册异步任务时添加的回调函数。

        // 消息队列中的消息就长这个样子
        var message = function () {
            callbackFn(response);
        }

主线程在执行完当前循环中的所有代码后,就会到消息队列取出这条消息(也就是message函数),并执行它。到此为止,就完成了工作线程对主线程的通知,回调函数也就得到了执行。

特别好的一个图,图片来源(https://sfault-image.b0.upaiyun.com/325/916/3259161542-575018ce29d44_articlex)用来说明上面的过程:
异步过程图

上面过程说了消息队列和事件循环,那什么是“事件”?事件在这里的概念实际上并不是必须的,事件机制实际上就是异步过程的通知机制。

好了~~第二个问题也解决了….撒花….普天同庆….

那就第三个问题啦

首先来说这个CommomJs,CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。这个CommonJS规范中有个Promise/A规范,注意啊这只是规范。何为规范就是一种约定俗成的模式,大家都遵守,这并没有具体的实现。所以才会有了各种库对于Promise/A的实现,如Jquery。

各个语言平台都有相应的 Promise 实现

  • Java’s java.util.concurrent.Future
  • Python’s Twisted deferreds and PEP-3148 futures
  • F#’s Async
  • .Net’s Task
  • C++ 11’s std::future
  • Dart’s Future
  • Javascript’s Promises/A/B/D/A+
    *

这个CommonJS的Promise/A规范是用来解决回调金字塔的问题。异步的实现主要有四种方式,一种是回调的方式,回调层层嵌套时会产生回调金字塔的问题,Promise机制呢是为了解决这个问题的另一种异步方式。

那Promise是什么呢?一个Promise是一个对象(注意是对象,以前我总是走眼不走心。。呜呜。。。是对象所以才有属性和方法啊,所以才会有经常出现的then方法)。

一个 Promise 对象代表一个目前还不可用,但是在未来的某个时间点可以被解析的值。它允许你以一种同步的方式编写异步代码。例如,如果你想要使用 Promise API 异步调用一个远程的服务器,你需要创建一个代表数据将会在未来由 Web 服务返回的 Promise 对象。唯一的问题是目前数据还不可用。当请求完成并从服务器返回时数据将变为可用数据。在此期间,Promise 对象将扮演一个真实数据的代理角色。接下来,你可以在 Promise 对象上绑定一个回调函数,一旦真实数据变得可用这个回调函数将会被调用。而Promise的then方法中放的就是回调方法。

promise 表示一个最终值,该值由一个操作完成时返回。
promise 有三种状态:未完成 (unfulfilled),完成 (fulfilled) 和失败 (failed)。
promise 的状态只能由未完成转换成完成,或者未完成转换成失败
promise 的状态转换只发生一次。
promise 有一个 then 方法,then 方法可以接受 3 个函数作为参数。前两个函数对应 promise 的两种状态 fulfilled 和 rejected 的回调函数。第三个函数用于处理进度信息(对进度回调的支持是可选的)。

promiseSomething().then(function(fulfilled){
      //当promise状态变成fulfilled时,调用此函数
  },function(rejected){
      //当promise状态变成rejected时,调用此函数
  },function(progress){
      //当返回进度信息时,调用此函数
  });

下面是个例子然后是机制解释:

var p = ???();//首先以某种方式拿到一个promise,假设这时p是pending的状态
var p1 = p.then(a,b);
var p2 = p1.then(c,d);

以上代码执行完之后,我们手里有3个promise:p,p1,p2.
这时,a,b,c,d都还没有执行。

在未来某个不确定的时间,如果p的resolve方法被调用了,接下来会发生的事情是:

  • p会把传给resolve方法的参数value记住,并把自己的状态标记为resolved (以后就再也不能变了),a会被调用到,其参数为value
  • 如果a执行过程中不出错, p1的状态被变成resolved,p1会把a的返回值记住
    c会被调用到,其参数为a的返回值
    
  • 如果c执行过程中不出错, p2的状态被变成resolved,p2会把c的返回值记住
  • 如果c执行过程中出错, p2的状态被变成rejected,p2会把c抛出的异常记住
  • 如果a执行过程中出错,p1的状态被变成rejected,p1会把a抛出的异常记,d被调用到,参数为a抛出的异常 - 如果d执行过程中不出错,p2的状态被变成resolved,p2会把d的返回值记住
  • 如果d执行过程中出错,p2的状态被变成rejected,p2会把d抛出的异常记住
    这样,就看出递归的意思来了。不过b并没有在上面出现,这是因为p本身是被resolve的,b只有在p被reject的时候才会执行。

在未来某个不确定的时间,如果p的reject方法被调用了,接下来会发生的事情是:
。。。 。。。

就不用写了,把上面的a替换为b就好了。

呐…..基本上第三个问题也解决啦…..

最后第四个问题~~

总算到最后一个问题啦,,,重中之重!!!既然Promise是规范,那怎样实现?上面说了那么多,实际是怎么样做啊?
根据上面执行机制的解释就很容易能看出递归来啦,所以实现肯定是用递归啦。。。

这里有一个 只要88行的代码实现Promise

那在常用的Jquery中异步是怎样实现的?
在Jquery中常用的异步主要就是ajax。那就是很常用的了。。。。。

参考文章

总结

以前发现自己做了很多无用功,问题出现了,甚至还没弄清楚问题具体是什么、根源究竟在哪里,就着急去解决,这肯定就会耗时长又不能解决问题。庆幸的是自己总算认识到了,估计以后的学习方法在我没有新的认识之前都会是这样的,先弄清楚自己的问题点在哪,然后对症下药。

文章目录
  1. 1. 首先是第一个问题:
  2. 2. 然后是第二个问题:
  3. 3. 那就第三个问题啦
  4. 4. 最后第四个问题~~
  5. 5. 参考文章
  6. 6. 总结