promise核心概念(一)

首先,要明确一点,Promise 是用来处理回调嵌套的问题,而不是用来处理回调本身的问题。

程序要素

通常,我们的程序有三个要素:

  1. 执行器
  2. 上下文
  3. 表达式

执行器按照语义规则在上下文中执行表达式,而表达式的最终效果都是要修改上下文,不修改上下文的表达式除了浪费时间之外,是没有意义的。 方法是表达式的集合,方法对上下文的修改可以表现在两个方面:

  1. 在方法体中直接修改了上下文的状态。
  2. 产生一个返回值,参与到接下来的表达式中。

所以,执行一个方法,最终的意义就是观察这个方法对上下文的修改结果,然后做出相应的动作。

同步与异步

同步方法的特征:

  1. 有直接的返回值,没有返回值的方法肯定直接修改了上下文。
  2. 可预期的异常栈,异常会沿着当前调用链向上传播。

异步方法的特征:

  1. 运行在另一个执行过程中,因此,异常不会沿着当前调用连向上传播。
  2. 没有直接的返回值,只能通过回调函数来观察修改结果。

对比下面的例子:

同步:

    var value = fn_1();
    var c = value_1 + 20;
    var value_2 = fn_2(c);
    console.log(value_2);
执行器 A 发起 fn_1 的调用, 执行器 A 执行并等待 fn_1 的执行完成,执行器 A 观察 fn_1 的结果。
执行器 A 发起 fn_2 的调用, 执行器 A 执行并等待 fn_2 的执行完成,执行器 A 观察 fn_2 的结果。

由于 fn_1 和 fn_2 都是同步方法,这个过程会很完美的工作。 但是,如果 fn_1 和 fn_2 都是异步方法,而异步调用根本就没有返回值,所以,这段代码是得不到预期效果的。 那我们就只能这么写了:

异步:

fn_1(function(value_1){
    var c = value_1 + 20;
    fn_2(c, function(value_2){
        console.log(value_2);
    })
})

虽然写法不一样,但是本质都是一样的,注意其中执行器的变化:

执行器 A 发起 fn_1 的调用,执行器 B 执行并等待 fn_1 的执行完成,执行器 A 观察 fn_1 的结果。
执行器 A 发起 fn_2 的调用,执行器 C 执行并等待 fn_2 的执行完成,执行器 A 观察 fn_2 的结果。

既然本质都是一样的,那么我们就可以将 “执行并等待 -> 观察”封装为一个概念——Promise,当异步方法的结果返回时,根据不同的结果,触发不同的动作。 形式如下:

var promise_1 = create_promise(fn_1);

var promise_2 = promise_1.then(function(value_1){
    var c = value_1 + 20;
    return create_promise(c, fn_2);
});

promise_2.then(function(value_2){
    console.log(value_2);
});

如此一来,就将异步的嵌套回调,转化为扁平的同步调用形式。