• Promise 对象


    es6 Promise 对象

    Promise 定义参考

    案例源码 戳这里

    ps:每个案例都是基于上一个改造的




    一、Promise 简介

    Promise 是一个对象,从它可以获取异步操作的消息

    案例1

    新建项目

    [demo]
      |-- src
        |-- index.html
        |-- index.js
      |-- webpack.config.js
      |-- package.json
    

    demo/package.json

    {
      "name": "webpack",
      "version": "1.0.0",
      "description": "",
      "scripts": {
        "dev": "webpack-dev-server",
        "build": "webpack -p"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "babel-core": "^6.26.0",
        "babel-loader": "^7.1.2",
        "babel-preset-es2015": "^6.24.1",
        "less-loader": "^4.0.5",
        "less": "^2.7.3",
        "style-loader": "^0.19.0",
        "css-loader": "^0.28.7",
        "extract-text-webpack-plugin": "^3.0.2",
        "html-webpack-plugin": "^2.30.1",
        "webpack": "^3.10.0",
        "webpack-dev-server": "^2.9.5"
      },
      "dependencies": {
        "jquery": "^3.3.1"
      }
    }
    

    demo/webpack.config.js

    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require("extract-text-webpack-plugin");
    
    module.exports = {
      entry: { // 入口文件地址
        index: './src/index.js'
      },
      output: { // 出口
        path: __dirname + "/build", // 打包后的文件存放路径
        filename: '[name].js' // 文件名,name即为entry的key
      },
      module: {
        loaders: [
          {
            test: /.(js)$/,  // js-loader
            loader: 'babel-loader?presets[]=es2015'
          },
          {
            test: /.css$/, // css-loader
            loader: ExtractTextPlugin.extract('css-loader')
          },
          {
            test: /.less/, // less-loader
            loaders: ExtractTextPlugin.extract('css-loader!less-loader')
          }
        ],
      },
      devServer: {
        contentBase: './build',
        inline: true,
        hot: true,
        before: (app) =>{
          app.get('/one.json', function(req, res) {
            res.json({ 
              user: 'promise',
              success: true
            });
          });
          app.get('/two.json', function(req, res) {
            res.json({ 
              age: '11',
              success: true
            });
          });
          app.get('/three.json', function(req, res) {
            res.json({ 
              hobby: 'basketball',
              success: true
            });
          });
        }
      },
      plugins: [
        new webpack.HotModuleReplacementPlugin(), // 启用热替换模块
        new HtmlWebpackPlugin({
          filename: 'index.html', // 生成的的html文件名
          template: './src/index.html', // 被打包的html路径
          chunks: ['index'] // 需要引入的js,对应entry的key
        }),
        new ExtractTextPlugin({ // 单独打包css
          filename: '[name].css'
        })
      ]
    }
    

    webpack 相关讲解戳这里

    demo/src/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Promise</title>
    </head>
    <body>
    </body>
    </html>
    

    demo/src/index.js

    // console.dir() 可以显示一个对象所有的属性和方法。
    console.dir(Promise)
    

    运行 npm i , 运行 npm run dev , 打开 http://localhost:8080 效果如下

    1

    从上面的图中,可以看出 Promise 是一个构造函数,有 all、race、reject、resolve 这几个方法,原型上有then、catch等方法

    Promise 的基本用法

    // Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject
    // resolve 异步操作执行成功后的回调函数 
    // reject 异步操作执行失败后的回调函数
    const promise = new Promise(function(resolve, reject) {
      // ... some code
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    // 用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数
    // then 方法可以接受两个回调函数作为参数, 第二个函数是可选的,不一定要提供
    promise.then(function(value) {
      // resolve 异步成功的操作
    }, function(error) {
      // reject 异步失败的操作
    });
    



    二、resolve、reject

    案例2

    demo/src/index.js

    import $ from 'jquery';
    
    const promise = new Promise(function(resolve, reject) {
      console.log('Promise');
    
      // 这里当 ajax 失败 ,或 success 不为 true 时,都认为是请求失败
      $.ajax({
        url: 'one.json',
        success: (data = {}) => {
          if (data.success) {
            resolve(data);
          } else {
            reject(data);
          }
        },
        error: (err = {}) => {
          reject(err);
        }
      })
    });
    
    promise.then(function(value) {
      console.log('resolved', value)
    }, function(error) {
      console.log('rejected', '请求失败')
    });
    

    效果如下

    2

    可以自己尝试下, 将 demo/webpack.config.js 里,one.json 请求的 success 改为 false , 如下

    {
      devServer: {
        before: (app) =>{
          app.get('/one.json', function(req, res) {
            res.json({ 
              user: 'promise',
              success: false
            });
          });
        }
      }
    }
    

    效果如下 (重启服务)

    3

    案例2 中,Promise 新建后立即执行,所以首先 console 打印的是 Promise。然后,then 方法里的函数,就相当于是我们平时的回调函数,只有在 promise 这个异步任务完成后才能执行,所以 console 打印的 resolved 和 rejected 在后面输出。


    案例3

    先对 案例2 进行一个简单的封装

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    // 传入 url
    getJSON({url: 'one.json'}).then(function(value) {
      console.log('resolved one', value)
    }, function(error) {
      console.log('rejected one', '请求失败')
    });
    

    效果和 案例2 一样

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    // 这里为了代码看的清除,只写了 then 方法里的第一个函数
    // 这样能够按顺序,输出每个异步回调中的内容
    getJSON({url: 'one.json'})
    .then((value) => {
      // one.json 请求成功拿到的结果
      console.log('resolved one', value);
    
      // 进行 two.json 请求
      // return 的是 Promise 对象
      // 这里的数据能在下一个 then 方法中拿到
      return getJSON({url: 'two.json'});
    })
    .then((value) => {
      // two.json 请求成功拿到的结果
      console.log('resolved two', value);
    }
    

    效果如下
    4

    第一个 then 方法中, return 的是 Promise 对象,也可以直接 return 数据,在下一个 then 方法中可以拿到数据,如下

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    getJSON({url: 'one.json'})
    .then((value) => {
      // one.json 请求成功拿到的结果
      console.log('resolved one', value);
    
      // return 的是 Promise 对象, two.json 请求的数据能在下一个 then 方法中拿到
      return getJSON({url: 'two.json'});
    })
    .then((value) => {
      // 直接返回数据
      console.log('two', value);
      return value;
    })
    .then((value) => {
      // two.json 请求成功拿到的结果
      console.log('resolved two', value);
    },(value) => {
      // two.json 请求失败拿到的结果
      console.log('rejected two', value);
    })
    

    效果如下

    5

    可以自己尝试下,将 demo/webpack.config.js 里,two.json 请求的 success 改为 false , 如下

    {
      devServer: {
        before: (app) =>{
          app.get('/two.json', function(req, res) {
            res.json({ 
              age: '11',
              success: false
            });
          });
        }
      }
    }
    

    效果如下

    6

    第二个 then 方法,不管 two.json 请求是成功还是失败,都会返回 value

    第三个 then 方法里,第一个函数是 two.json 请求成功时调用,第一个函数是 two.json 请求失败时调用




    三、catch

    和 then 的第二个参数一样,用来指定 reject 的回调

    案例4

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    getJSON({url: 'one.json'})
    .then((value) => {
      // one.json 请求成功拿到的结果
      console.log('resolved', value);
    })
    .catch((reason) => {
      // one.json 请求失败拿到的结果
      console.log('rejected', reason);
    });
    

    效果如下

    7

    可以自己尝试下, 将 demo/webpack.config.js 里,one.json 请求的 success 改为 false ,就可以看到 rejected 的效果, 如下

    8

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    getJSON({url: 'one.json'})
    .then((value) => {
      // one.json 请求成功拿到的结果
      console.log('resolved', value);
      // 这里 aaa 未定义
      console.log(aaa);
    })
    .catch((reason) => {
      console.log('rejected');
      // one.json 请求失败拿到的结果
      console.log('reason', reason);
    });
    

    效果如下

    9

    aaa 未定义,如果不写 catch 部分代码运行到这里就会报错, 不往下运行了,如下

    10

    写了 catch 后,这里就进入了 catch ,并且将报错原因也传到 reason 中去了

    reason ReferenceError: aaa is not defined
    

    这么写,即便是有错误的代码也不会报错,和 try/catch 相同。

    一般来说,不要在 then 方法里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用catch方法。




    四、finally

    finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

    案例5

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    getJSON({url: 'one.json'})
    .then((value) => {
      // one.json 请求成功拿到的结果
      console.log('resolved', value);
    })
    .catch((reason) => {
      // one.json 请求失败拿到的结果
      console.log('rejected', reason);
    })
    .finally(() => {
      console.log('finally')
    });
    

    效果如下

    11

    reject 的情况大家自己尝试




    五、Promise.all()

    提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调

    案例6

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    // all接收一个数组参数
    Promise
    .all([getJSON({url: 'one.json'}), getJSON({url: 'two.json'})])
    .then((data) => {
      console.log('resolved', data);
    })
    .catch((err) => {
      console.log('rejected', err);
    })
    .finally(() => {
      console.log('finally')
    });
    

    all 接受一个数组作为参数,里面的值最终都算返回Promise对象

    效果如下

    12

    当这两个请求都请求成功后,就进入 then 里,返回的结果是把两个请求的结果塞入一个数组中去了。

    Promise.all() 可以并行执行多个异步操作,并且在一个回调函数中能拿到所有的返回结果。

    当 one.json 和 two.json 的 success 都为 false (webpack.config.js里修改),结果如下

    13

    当 one.json 的 success 为 false, two.json 的 success 为 true ,结果如下

    13

    当 one.json 的 success 为 true, two.json 的 success 为 false ,结果如下

    14

    从这些可以得出,all里,只要有一个被 rejected,就会走到 catch 里去,catch 里 console 的值,是第一个被 rejected 的返回值




    六、 Promise.race()

    写法和 Promise.all() 类似,区别在于,race 里的异步操作,谁先完成,then 里的返回值就是谁的。

    案例7

    demo/src/index.js

    import $ from 'jquery';
    
    const getJSON = (opts) => {
      // ajax 需要的参数都可以写在 opts 里
      console.log('opts', opts)
      const {
        url = '',
        type = 'GET',
      } = opts;
      const promise = new Promise(function(resolve, reject) {
        $.ajax({
          url,
          type,
          success: (data = {}) => {
            if (data.success) {
              resolve(data);
            } else {
              reject(data);
            }
          },
          error: (err = {}) => {
            reject(err);
          }
        })
      });
      // 返回一个Promise对象
      return promise;
    }
    
    // all接收一个数组参数
    Promise
    .race([getJSON({url: 'one.json'}), getJSON({url: 'two.json'})])
    .then((data) => {
      console.log('resolved', data);
    })
    .catch((err) => {
      console.log('rejected', err);
    })
    .finally(() => {
      console.log('finally')
    });
    

    结果如下

    15

    one.json 先求情完毕,then 里的 console 打印出来的就是 one.json 返回的结果。

    如果给 $.ajax 外层包一个 setTimeout ,且判断下如果是 one.json 的时候就延迟一秒,如下

    setTimeout(()=>{
      $.ajax({
        url,
        type,
        success: (data = {}) => {
          if (data.success) {
            resolve(data);
          } else {
            reject(data);
          }
        },
        error: (err = {}) => {
          reject(err);
        }
      })
    }, url === 'one.json' ? 1000 : 0)
    

    效果如下
    16

    这里 two.json 先请求完毕,因此 then 里的 console 打印出来的就是 two.json 返回的结果。

    (ps: 下面是不加 setTimeout 的三种情况)

    当 one.json 和 two.json 的 success 都为 false (webpack.config.js里修改),结果如下

    13

    当 one.json 的 success 为 false, two.json 的 success 为 true ,结果如下

    13

    当 one.json 的 success 为 true, two.json 的 success 为 false ,结果如下

    15

    从这些可以得出,race 里:

    1. 最快完成的那个,如果走到 rejected,不管后面是 rejected 还是 resolved, 都会进入 catch , 且 catch 里 console 的值,就是最快被 rejected 的值

    2. 最快完成的那个,如果走到 resolved,不管后面是 rejected 还是 resolved,
      都会进入 then , 且 then 里 console 的值,就是最快被 resolved 的值

    上面的几种情况,如果你注意看 Network 的话,就会发现,不管 one.json 有没有执行成功,two.json 的请求都还是会发送

    17

    我们也可以通过在 ajax 里打印 console 来看,如下

    $.ajax({
      url,
      type,
      success: (data = {}) => {
        if (data.success) {
          resolve(data);
          console.log('请求成功', url)
        } else {
          reject(data);
          console.log('请求失败', url)
        }
      },
      error: (err = {}) => {
        reject(err);
        console.log('请求失败', url)
      }
    })
    

    效果如下

    18

    当 then 里的回调开始执行时,getJSON({url: 'two.json'}) 并没有停止,仍旧再执行。




    七、Promise.resolve()

    有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用

    具体参考戳这里

    案例8

    demo/src/index.js

    const obj = {
      a: 1,
      b: 2
    }
    
    const promise = Promise.resolve(obj);
    
    console.log(promise)
    
    promise.then((v) => {
      console.log(v)
    })
    

    结果如下

    19




    八、Promise.resolve()

    Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

    具体参考戳这里

    案例9

    demo/src/index.js

    const obj = {
      a: 1,
      b: 2
    }
    
    const promise = Promise.reject(obj);
    
    console.log(promise)
    
    promise.then(v => {
      // do nothing
    }, v => {
      console.log(v)
    })
    
    promise.catch(v => {
      console.log(v)
    })
    

    结果如下

    20

  • 相关阅读:
    fastjson ,json格式的String 转map
    linux下查找某个文件的位置
    springboot yml配置文件数据库密码加密
    post请求 formdata类型请求数据 springboot restTemplate
    SpringBoot 获取POST请求参数详解(附样例:表单数据、json、数组、对象)
    java有参的构造方法和无参的构造方法
    <转载>跨线程进行Windows窗体控件的访问
    大疆车载从多家数据库中选定 TDengine
    一文读懂TDengine的窗口查询功能
    开源代码难阅读?几位研发的“妙招”帮你解决
  • 原文地址:https://www.cnblogs.com/sakurayeah/p/8945199.html
Copyright © 2020-2023  润新知