美文网首页
9.promise 了解与应用

9.promise 了解与应用

作者: wudimingwo | 来源:发表于2018-12-08 13:59 被阅读0次

为什么用promise? 用来干什么的?
异步编程,想要解决执行顺序问题, 一般都用回调函数

回调函数嵌套太多,
就会形成 v形代码, 称为回调地狱.
回调本质上是把函数当做参数传给另一个函数,
从直观上来讲, 他是一个嵌套结构, 而不是线性结构,
嵌套结构太多, 非常不好阅读

所以实际上 promise 是用来管理回调函数的,
而管理回调函数可以用在同步,也可以用在异步
只是用在异步时, 体验会相当的好?

通过 设置状态,进行降维, promise 是用来管理状态的?

v形代码
降维之后

思考
昨天学习 es6生成器的时候, 在最后一段学习中,
我们用生成器来管理了一下异步执行的顺序,
或者说我们让 嵌套结构降维, 变成了线性结构.
但用生成器的时候, 实际上没有定义什么变量是用来标记状态的.
而且我们完成下一个操作的方式是, 当完成前一个就直接执行下一个.

而promise 则是有一个叫状态的中间量.
每完成一个步骤, 就会返回一个状态,
不同的状态里, 注册着不同的函数,
一旦返回某个状态就会相应执行 该状态里的函数.
也就是监听了这个状态
似乎和之前在设计模式当中学过的 观察者模式很像.

            let some = new Promise((resolve,reject) => {
              reject(14);
//            resolve(13);
            });
            
            some.then(
              (data)=> {
              console.log('success');
              console.log(data);/13
            },
            (data) => {
              console.log('fail');
              console.log(data);/14
            }
              
            )

可以看出

  • resolve,reject 两个函数是专门用来更改状态的.
  • then(fn1,fn2) 是对应的状态要执行的函数
  • resolve(参数) 会传到对应的函数
            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
              reject('fail');
            });
            
            let s2 = s1.then(
              (data)=> {
              console.log(data);
            },
            (data) => {
              console.log(data);
            }
              
            )
            
            console.log(s2 == s1);/ false
            console.log(s1);
            console.log(s2);

s1.then() 执行之后,默认会返回一个新的 promise实例对象

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              return new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
                  
                },1000)
              })
              
            },
            (data) => {
              console.log(data);
            }
              
            )
            
            s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
image.png

在then的回调函数中return 一个new Promise 会取代默认的promise 对象
仔细观察会发现, then里的回调函数,的执行顺序在 s2 == s1之后
表明 then里注册的函数是开启了异步线程?
测试, 如果在then 回调函数中返回其他值, 会怎么样?

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
                  
                },1000)
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            
            s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);/false
            console.log(s2 == s3);/false

打脸, 我们惊奇的发现 s2 !== s3
这表明什么呢?...
这表明 s1.then() 里的返回值根本就不会传给 s2?
实际上 s2 是会返回一个默认的promise 对象?
可怎么解释, s2能够监听 s3的状态?

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
                  
                },1000)
                s3.then((data) => {console.log(data);},(data) => {console.log(data);})
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            console.log(s2);
            s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
            console.log(s2 == s3);
image.png

神奇的地方出现了.
我们发现 在增加了 s3.then() 之后, s2.then() 报错了?
从执行顺序上来看,
在主线程进行的时候, s2 确实是一个 promise 对象
但在另一个线程当中, 读取到 s3.then()的语句时, s2突然就变成了undefined

测试一下, 如果把 s2.then() 去掉会如何?

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
                  
                },1000)
                s3.then((data) => {console.log(data)},(data) => {console.log(data);})
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            console.log(s2);
           // s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
            console.log(s2 == s3);

image.png

我们发现他是会报错的.
对于此,我们只能暂时假设为, then() 里不能嵌套 then() ?
测试, 我们再给 s3.then() 换个地方
废话当然会报错, s3 还没被赋值...

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
// 这里的代码会在异步线程里读,那个时候,已经被赋值
// 当然不会报错..
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
                  
                },1000)
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            console.log(s2);
//          s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
            console.log(s2 == s3);
image.png

惊奇的发现没有报错!(当然不会报错,惊奇啥..)
测试, 再把s2放回来

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  resolve("suc2");
//                reject('fail1');
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
console.log(s3 == s2);/false                  
                },1000)
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            console.log(s2);
            s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
            console.log(s2 == s3);
image.png

发现这次不仅没有报错, 而且两个监听函数都被执行了
两个promise 监听了 同一个状态.
该怎么解释呢?
推测是这样的, 首先 s2 !== s3 表明是不同的promise 实例
但每个promise 实例会共享 resolved rejected 状态
推测 状态没在实例上定义 而在Promise原型上定义了.
所以能够进行状态共享.

测试, 如果以上推测属实, 是否会出现 s1能够监听后来的 s2?s3?

            let s1 = new Promise((resolve,reject) => {
              resolve("suc");
//            reject('fail');
            });
            let s3;
            let s2 = s1.then(
              (data)=> {
              console.log(data);
              s3 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  //                resolve("suc2");
                  reject('fail2');
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
s1.then((data) => {console.log(data)},(data) => {console.log(data);})
                  
                },1000)
              })
              return s3
            },
            (data) => {
              console.log(data);
            }
              
            )
            console.log(s2);
            s2.then((data) => {console.log(data);},(data) => {console.log(data);})
            
            
            
            console.log(s2 == s1);
            console.log(s2 == s3);
image.png

表明刚才的结论是错的
也就是, 不同实例之间, 他们的状态是不共享的
那么为什么 s2 和 s3 的状态会共享?
可能的原因是, s2 接收 return 的 s3 时, 虽然两个实例不一样,
但他们之间会共享 状态?
我已经彻底把自己弄懵逼了.
这时你就会发现, 很多时候如果直接弄懂源码就会明白为什么会有各种各样的行为.
如果不知道源码, 就会用各种测试不停的得到各种边边角角的迹象,然后要不停去猜, 实际上, 这个过程相比学习源码而言,效率是低很多的.
因为即使通过这种方式一定程度掌握了工具, 使用时的成本可能也会更高.


回到正题

链式调用 then()

            let s1 = new Promise((resolve,reject) => {
              console.log('start');
              resolve("suc");
//            reject('fail');
            }).then(
              (data)=> {
              console.log(data);
              return new Promise((resolve,reject) => {
                setTimeout(() => {
                  //                resolve("suc2");
                  reject('fail2');
                },1000)
              })
            },
            (data) => {
              console.log(data);
            }).then(() => {},(data) => {console.log(data);})
image.png

用promise 封装$.ajax

            function myAjax (url,data=null,type="GET") {
                return new Promise(function (resolve, reject) {
                    $.ajax({
                        type,
                        url,
                        data,
                        async:true,
                        success (data) {
                          resolve(data);
                        },
                        error (err) {
                          reject(err);
                        }
                    });
                })
            }
            
            let p = myAjax('www.baidu.com');
            p.then((data) => {console.log(data);},(err) => {console.log(err);});
            p.then((data) => {console.log(data);},(err) => {console.log(err);});

我感觉到了这个有很大的好处,
但我还无法说清楚哪里好
所以我们试着去想一想, 都有哪些好处?

            let p = new Promise((res,rej) => {
              res('data');
            })
            
            p.then((data) => {console.log(data);},(err) => {console.log(err);});/ data
            p.then((data) => {console.log(data);},(err) => {console.log(err);});/ data
  • 之前接触回调的用法, 一个很强烈的感受是, 数据找功能函数.
  • 而用promise 之后,感觉有回到了 函数调用数据的感觉. 这种感觉本身似乎更自然?
  • 本来需要定义两个回调函数的, 现在可以清晰的分开来?
            let p = new Promise((res,rej) => {
              res('data');
            })
            
            p.then((data) => {console.log(data);
               return new Promise((res,rej) => {
                 setTimeout(function () {
                    res('分支1')
                 },1000)
                 
               });
            },(err) => {console.log(err);})
            .then((data) => {console.log(data);});
            
            
            
            p.then((data) => {console.log(data);
              return new Promise((res,rej) => {
                 setTimeout(function () {
                  res('分支2')
                 },2000)
                 
               });
            },(err) => {console.log(err);})
            .then((data) => {console.log(data);});
  • 可以用 在then( ) 的回调函数中 添加 return new Promise 的方式
    线性添加异步任务?

疑问, then()回调里面是没有 res,rej 函数的?
那就是说, 我想要then()监听一个异步, 就必须要开启一个return new Promise?
这感觉不是很方便啊.

相关文章

  • 9.promise 了解与应用

    为什么用promise? 用来干什么的?异步编程,想要解决执行顺序问题, 一般都用回调函数回调函数嵌套太多,就会形...

  • Day5

    学习内容:指针的概念与应用收获: 了解了内存的相关概念; 了解了指针的相关概念; 了解了指针变量的使用; 了解了字...

  • 交互设计原则

    一、减少认知负担 用户与应用交互时的阻力和困惑越少,应用被继续使用的机会就越大。 二、优化交互流程 了解用户如何与...

  • 应用监控大屏

    应用监控大屏 系统应用的监控、在线率、响应时间、智能运维服务链、提高办公应用与的情况基本信息了解。 监控大屏主要运...

  • APP手工测试01

    学习目标 - 掌握APP专项测试要点- 了解APP应用内测发布环境- 了解APP应用线上发布环境- 掌握APP应用...

  • IoC 容器的初始化之 BeanDefinition 的 Re

    之前我们大概了解 Spring 中关于 IoC 容器的设计与应用。接下来我们就要从源代码出发,详细了解 Sprin...

  • App的教学运用学习感悟

    感谢晓粧老师的细心讲解,让我深刻领会了app的应用性,通过本次学习了解了app的分类,应用及其在实际应用中的体现与...

  • 设计模式之策略模式代码实战

    课程目标 了解代码重构 了解策略模式的定义、应用场景 了解JDK中策略模式的应用 了解设计原则(开闭原则、单一职责...

  • golang 如何通过unsafe.Pointer uintpt

    主要是对unsafe.Pointer uintptr的一个应用实例,顺便了解golang的string与slice...

  • 2017.3.24日易效能20期二阶第一天课程总结

    今天课程分享:1、深入学习OmniFocus 和日历的进一步应用。深入了解各个功能及应用场景等。2、记录与反思的补...

网友评论

      本文标题:9.promise 了解与应用

      本文链接:https://www.haomeiwen.com/subject/dvofhqtx.html