Promise 源码分析

从源码里分析 promise 奇特的特性。

        1、promise 基本概念就不介绍了,es6,解决套套问题。。

        2、本文主要记录下自己遇到的不懂的地方记录下,并没有全面去讲解。

        3、外部一种实现promise的源码:https://github.com/ygm125/promise/blob/master/promise.js

            先看个小例子的,

var promise = Promise.resolve(1);
promise.then(function(a){console.log(a,1);}).then(function(a){console.log(a,2)})
  //在浏览器console执行的结果:
    1 1
    undefined 2 
  //promise库执行的结果:
    1 1
    1 2

            显然,浏览器自己实现的 promise 和外部promise库的实现方案还是有细微差别的。但是这种差别不属于promise规范的范畴,你也可以实现自己更好用更多用途的。promise规范规定必须要异步的,浏览器实现的promise应该用的是浏览器内部的一些特性(不知道具体是什么),,,但是外部 promise 在 js 层面代码层面上怎么实现异步的呢,答案是:setTimeout()。。。

           

promise的三种状态:pending、fullfilled,rejected。

            promise构造函数的参数resolver,即是你自己的逻辑过程函数,该函数有两个参数,这两个参数会传与promise静态函数resolve和reject,你自己的逻辑过程函数逻辑(无论异步还是同步)写完后,记得在合适的地方调用这两个函数(这两个函数对应有自己的回调函数)即可,表示我的承诺已经给出来了。时机成熟时,调用处就是整个promise.then链条的发动处。

            promise.resolve和reject动作对应的回调函数需要你自己注册进去的。

            这个注册操作就是then函数了。

            但是为什么可以把回调函数放到未来去注册?

            理由是:异步(setTimeout异步或者浏览器自己的实现),确保了then()函数肯定在链条启动前就执行了!

then函数:

每then一次,都会返回一个新的promise对象。每次then的时候,首先判断调用者promise的状态:

  • 如果是pending,就把fullfill和reject回调注册进去;     如,wait(1000).then(function(x){console.log(x,1)}),初始状态是 pending
  • 如果是fullfill,就把fullfill后的值立即传给fullfill回调函数处理;     如,Promise.resolve(1).then(function(x){console.log(x,1)}),初始状态是 fullfill
  • 如果是reject,就把reject后的值立即传给reject回调函数处理。     如,Promise.reject(1)..then(function(x){console.log(x,1)}),初始状态是 reject

            这个then函数实现了一个特殊的地方见代码:68-77行,在于:你的fullfill回调有三种可能:

  • 是值,不是函数。那就不执行函数,把你传入的值当作当前promise fullfill状态的结果值,resolve一下。
  • 是函数、没有返回值。执行函数,promise当前值不变,resolve一下。
  • 是函数、有返回值。执行函数,把函数返回值当作promise的值,resolve一下。
  • 是函数、有返回值、返回值是thenable的(就是含有then方法的对象)。执行函数,给返回的proimse对象简单的then一下,这个then就是透传当前promise的值。

            then里面有递归,还不同于一般的递归,不是可以很直观理解。这个递归决定了这个then可以有多种多样的then链条。

举例子:

function doubleUp(value) {
 return value * 2;
}
function increment(value) {
 return value + 1;
}
function output(value) {
 console.log(value);// => (1 + 1) * 2
}
var promise = Promise.resolve(1);
promise
 .then(increment)
 .then(doubleUp)
 .then(output)
 .catch(function(error){
 // promise chain中出现异常的时候会被调用
 console.error(error);
 });

再举例子:

function sleep(msecond){
    return new Promise(function(a,b){
        setTimeout(a,msecond);
    });
}

//var promise = Promise.resolve(1);
var promise = sleep(1000);
promise.then(function(x){
    console.log(x,1);
    return Promise(function(a,b){
        b(x);
    });
}).then(function(x){console.log(x,2)})
.then(function(x){console.log(x,3)},function(x){console.log(x,4)})

还有更多各种嵌套的,都可以行的通。

▲ then链条如何保证顺序

1、promise1对象有了,显然是执行到setTimeout等待步骤了,状态是pending,timeout完成,立马就是fullfill状态并执行fullfill回调 函数func1

2、由于是异步,promise.then(func1)会在timeout完成前执行。

3、promise.then(func1)会新建promise2,即 new promies(resolver)。我们知道,在你的resovler代码里需要调用resovle函数才能使promise进入到setTimeout等待中。

4、链条连接点:func1里的新的promise2的resovler代码只有在promise状态为fullfill时才能执行。

5、也就是,只有promise1状态完成时,新的promise2才能进入setTimeout等待。

6、依次类推,,一环扣一环,,保证了链条有序执行。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏偏前端工程师的驿站

前端魔法堂——异常不仅仅是try/catch

前言  编程时我们往往拿到的是业务流程正确的业务说明文档或规范,但实际开发中却布满荆棘和例外情况,而这些例外中包含业务用例的例外,也包含技术上的例外。对于业务用...

2667
来自专栏企鹅号快讯

PHP中被忽略的性能优化利器:生成器

如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生。但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP5.5.0才引入的功能,也...

38614
来自专栏好好学java的技术栈

代理模式,看这篇文章足够了

生活中:代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间...

671
来自专栏大前端_Web

javascript的replace+正则 实现ES6的字符串模版

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

904
来自专栏申龙斌的程序人生

零基础学编程008:print语句

在《零基础学编程007:FOR循环》这一篇文章里,我们只写了两行代码: for i in [1,2,3,4,5] : print( "(1+0.01)...

2907
来自专栏积累沉淀

Java设计模式(八)----代理模式

代理描述 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对...

1989
来自专栏从流域到海域

《笨办法学Python》 第20课手记

《笨办法学Python》 第20课手记 本节课讲函数与文件,内容比较简单,但请注意常见问题解答,你应该记住那些内容。 指针表示存储地址。 原代码如下: from...

1986
来自专栏飞雪无情的博客

Go语言 | Go 1.9 新特性 Type Alias详解

北京时间2017.08.25,Go1.9正式版发布了。Go1.9经历了2个beta,好几个月,终于定了,发布了正式版本。Go 1.9包含了很多改变,比如类型别名...

974
来自专栏抠抠空间

模板语言

常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}。 变量 {{ 变量名 }} 变量名由字母数字和下划线组...

3478
来自专栏猿人谷

总结c++ primer中的notes

C++ Primer, Fourth Edition (中英文)下载地址:http://download.csdn.net/detail/ace_fei/416...

2019

扫码关注云+社区