zoukankan      html  css  js  c++  java
  • Promise 一自我总结

    最近一下班就没有持续学习,已经持续了几个月,回家就是练练字,看看书,干些七七八八的事。这样的生活总感觉空落落的,毕业半年了,总感觉自己很多东西明白的不清不楚,希望接下来的每一天都能扎扎实实学好。

    一、出现前景,Promise是什么

    • 出现前景:在一个单线程的世界,为了支持异步编程,于是Js使用了回调,然而回调带来的问题就是我们经常听到的什么地狱回调,金字塔等问题。有问题就会有解决方案,所以就出现了Promise。
    • 概念:异步编程的一个解决方案 

    二、基本使用规则

    ES6 规定,Promise对象是一个构造函数,用来生成Promise实例

    const promise = new Promise(function(resolve, reject) {
      if (操作成功){
         resolve(value);
      } else {
         reject(error);
      }
    });

    从上面代码可以看到Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,此外这两个参数是连两个函数,由JS引擎提供。

    那么这两个函数的作用是:

      (1) resolve: 将Promise对象的状态从未完成变成成功,异步操作成功时调用。

      (2) reject: 将Promise对象的状态从未完成变成失败,异步操作失败时调用。

    当Promise实例生成后,就可以用then方法指定resolve状态和reject状态的回调函数,then方法接受两个回调函数作为参数:

    第一个回调是当Promise对象的状态为resolve时调用

    第二个回调函数是当Promise对象的状态为reject时调用,第二个回调函数可选

    基本案例:

    var promise = new Promise(function(resolve, reject) {
      resolve()
      console.log('我是当前脚本的同步任务,then方法指定的回调函数等下我,你的在我后面排队')
    })
    promise.then(function(resolve) {
      console.log('promise的状态为resolve,所以我被调用出来啦')
     },function(reject) {
      console.log('promise的状态为reject,我才会出来哦,这次我就不参与')
    })
    
    
    结果输出:
    我是当前脚本的同步任务,then方法指定的回调函数等下我,你的在我后面排队
    promise的状态为resolve,所以我被调用出来啦

    Promise.prototype.then()

    Promise 实例具有then方法, 那么then方法是定义在原型对象promise.prototype上的
    then方法返回的也是一个新的Promise实例,因此可以采用链式写法,即then方法后面再调用另一个then方法

    run1.then(function(data) {
       console.log(data + ':第一个输出')
       return run2();
     }).then(function(data) {
       console.log(data + ':第二个输出')
       return run3()
    }).then(function(data) {
       console.log(data + ':第三个输出')
    })

    上面的代码使用then方法,第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

    Promise.prototype.catch():

    用于指定发生错误时的回调函数

    run1.then(function(data) {
       return run2();
    }).catch(function(data) {
       console.log('前方有异常')
    })

    看到这里的时候,可能会觉得promise对象不是有一种失败调用的reject函数么,如下格式:

    run1.then(function(data) {
       return run2();
    }, function(data) {
       console.log('异常调用')
    })

    对比这两种写法,第一种写法要好于第二种写法,理由是通过catch可以捕获前面then方法执行中的错误,更接近同步的写法(try/catch)。

    因此,建议总是使用catch方法,而不使用then方法的第二个参数。

    下面是一个用Promise对象实现的 Ajax 操作的例子:

      function getData(url) {
        let promise = new Promise(function(resolve, reject) {
          const handler = function() {
            if (this.readyState !== 4) {
              return
            }
            if (this.status === 200) {
              resolve(this.response)
            } else {
              reject(new Error(this.responseText))
            }
          }
          let temp = new XMLHttpRequest()
          temp.open('get', url)
          temp.onreadystatechange = handler;
          temp.setRequestHeader("Accept", "application/json");
          temp.send()
        })
        return promise
      }
      
      getData('http://yapi.demo.qunar.com/mock/37644/testDat').then(function(data){
        console.log(data)
        return '12'
      }).then(function(data) {
        console.log(data)
      })

    三、手写一个promise

    * 同步操作,且then只能调用一次

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>同步操作,且then只能调用一次</title>
    </head>
    <body>
    
    <div id="box">12</div>
    <script>function Promise(exector) {  // 创建一个构造构造函数
          let self = this;
          this.value = undefined;
          this.reason = undefined;
          this.status = 'pending';
          function resolve(value) { // 此function this指向window
            if (self.status === 'pending') {
              self.value = value;
              self.status = 'resolved';
            }
          }
          function reject(reason) {
            if (self.status === 'pending') {
              self.reason = reason;
              self.status = 'rejected';
            }
          }
          try {
            exector(resolve, reject)
          } catch(e) {
            reject(e)
          }
        }
        Promise.prototype.then = function(onFulfilled, onRejected) {  // then方法添加到构造函数的原型上
          let self = this;
          if (this.status === 'resolved') {
            onFulfilled(self.value)
          }
          if (this.status === 'rejected') {
            onRejected(self.reason)
          }
        }
    
        let promise1 = new Promise(function(a, b) {
          a('ha')
        })
        promise1.then(data => {
          console.log('success')
          console.log(data); 
        }, err=> {
          console.log('error')
          console.log(err);
        })
    </script>
    </body>
    </html>

    显然我们平时用的都是异步的方式,再来改改。需要在构造函数中存放两个数组,分别保存成功回调和失败的回调 因为可以then多次,所以需要将这些函数放在数组中

    * 异步操作,且then只能调用一次

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>异步操作,且then只能调用一次</title>
    </head>
    <body>
    
    <div id="box">12</div>
    <script>
        function Promise(exector) {  // 创建一个构造构造函数
          let self = this;
          this.value = undefined;
          this.reason = undefined;
          this.status = 'pending';
          this.successCallBack = [];
          this.failCallBack = [];
          function resolve(value) { // 此function this指向window
            if (self.status === 'pending') {
              self.value = value;
              self.status = 'resolved';
              console.log(self.successCallBack)
              self.successCallBack.forEach((fn) => { fn() }) // 遍历then中成功的所有回调函数
            }
          }
          function reject(reason) {
            if (self.status === 'pending') {
              self.reason = reason;
              self.status = 'rejected';
              self.failCallBack.forEach((fn) => { fn() }) // 遍历then中失败的所有回调函数
            }
          }
          try {
            exector(resolve, reject)
          } catch(e) {
            reject(e)
          }
        }
        Promise.prototype.then = function(onFulfilled, onRejected) {  // then方法添加到构造函数的原型上
          let self = this;
          if (this.status === 'resolved') {
            onFulfilled(self.value)
          }
          if (this.status === 'rejected') {
            onRejected(self.reason)
          }
          if (this.status === 'pending') {
            this.successCallBack.push(() => {
              onFulfilled(self.value)
            })
            this.failCallBack.push(() => {
              onRejected(self.reason)
            })
          }
        }
    
        let promise1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            if(Math.random() > 0.5) {
              resolve('成功');
            } else {
              reject('失败');
            }
          }, 1000)
        })
    
        promise1.then(data => {
          console.log('success')
          console.log(data); 
        }, err=> {
          console.log('error')
          console.log(err);
        })
    </script>
    </body>
    </html>

    * 异步操作,then可以链式调用

  • 相关阅读:
    BZOJ 3205 [Apio2013]机器人 ——斯坦纳树
    BZOJ 3782 上学路线 ——动态规划 Lucas定理 中国剩余定理
    HDU 1423 Greatest Common Increasing Subsequence ——动态规划
    BZOJ 3309 DZY Loves Math ——莫比乌斯反演
    POJ 1038 Bugs Integrated, Inc. ——状压DP
    POJ 3693 Maximum repetition substring ——后缀数组
    POJ 2699 The Maximum Number of Strong Kings ——网络流
    POJ 2396 Budget ——有上下界的网络流
    BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
    源码安装python
  • 原文地址:https://www.cnblogs.com/Tiboo/p/10072963.html
Copyright © 2011-2022 走看看