zoukankan      html  css  js  c++  java
  • Promise对象

    promise对象用来管理异步操作(未来某个时刻发生的事),由Promise构造函数生成,有一些内置的api,通过这些api能以同步的代码书写方式来表示异步操作,避免不断嵌套的回调函数的书写方式。可以把Promise对象看做一个容器,里面保存着异步操作的结果。
    promise对象用三种状态来表示异步操作的状态:pending(进行中),resolved(已完成),rejected(失败了,抛出错误了),状态只能由pending变成resolved或由pending变成rejected,通过promise对象的api可以(提前)指定当变到resolved或rejected状态时的回调函数,而什么情况下是resolved状态,什么情况下是rejected状态,可以由我们自己决定。

    主要api:

      1.生成一个primise对象(实例):

    var p = new Promise(function(resolve, reject) {
      // 一些异步操作, 得到操作结果result
      var result = ...
      if (result == 'ok') { // 设置这种情况下调用resolved的回调函数
        resolve(result)
      } else {
        reject('not ok')
      }
    })

      其中的resolve, reject分别表示resolved和rejected时的回调函数,并且可以传任意参数。如代码所示,当执行resolve(result)时即是把promise对象的状态变成resolved状态,当执行reject('not ok')时即是把promise对象的状态变成rejected状态.

      2.Promise.prototype.then()设置resolved和rejected的回调函数

    p.then(function(val) {
      console.log(val)  // 'ok'
    }, function (val) {
      console.log(val) // 'not ok'
    })    

      then方法接受两个函数参数,第一个参数就是resolved的回调函数,第二个参数是rejected的回调函数(第二个参数是可选的)

    一个简单的例子:

    var p = new Promise((resolve, reject)=>{
      var result = true
      var v='aaa '
      if(result) {
        resolve(v)
      } else {
        reject(v)
      }
    })
    p.then( v => console.log(v+'resolve')  // 'aaa resolve'
    , v => console.log(v+'reject') )// 'aaa reject'

    一个简单的例子:

    console.log(0)
    var demo = function(){
      return new Promise((resolve, reject) => {
        setTimeout(resolve, 5000, 'aaa ')
      })
    }
    demo().then( v => console.log(v+'resolve'), v => console.log(v+'reject'))
    console.log(1)
    
    // 运行结果
    0
    1
    (5s后) 'aaa resolve'

    一个异步加载图片的简单例子:

    function loadImgAsync (url) {
      return new Promise( (resolve, reject) => {
        var img = new Image()
        img.onload = ()=> resolve(img)
        img.onerror = () => reject(new Error('not ok'))
        img.src = url
      })
    }
    var url = 'http://img3.duitang.com/uploads/item/201509/02/20150902131938_yEJVA.jpeg'
    loadImgAsync(url).then(() => console.log('ok'), err => console.log(err.message) )

     .then()方法返回的是一个新的Promise实例,所以可以采用链式写法,.then().then(),前一个then回调函数的return返回值会作为参数传到后一个then的回调函数里,只有当前一个Promise对象状态发生变化才会调用下一个then的方法。

    一个简单的例子:

    p.then( () => {
        console.log('resolve1')  
        return 111
    }, () => {
        console.log('reject1')
        throw "empty"
    }).then( v =>  console.log(v+' resolve2'), v => console.log(v+' reject2') )
    
    // 若p执行resolved, 则依次 'resolve1', '111 resolve2' 
    // 若p执行rejected, 则依次 'reject1', '111 reject2' 
    // 若p执行rejected, 同时注释掉throw "empty"或换成 return new Error(),则会依次 'reject1', ' resolve2'!!!

    由此可见只有在程序抛出异常或是Promise对象中手动指定调用reject(),只有这两张情况下会执行reject()。

    比如: 假设getJson(url)会返回一个Promise对象,用来执行ajax操作,成功时返回结果作为参数传给resolve函数,失败时返回一个Error对象传给reject函数。

    getJSON('/post/1.json')
    .then(post => getJSON(post.commentUrl))
    .then( comment => console.log(comment), err => console.log(err) )

    上例就是先取post信息,取到后再去取comment信息。

    3.Promise.prototype.catch((err)=>{})

    异步操作抛出错误时的回调函数,相当于.then(null, rejectFun),错误具有'冒泡'特性,会一直向后传递,所以:

    p
    .then()
    .then()
    .catch((err)=>{
    // 处理前面三个promise产生的错误
    })

     一般来说,不推荐p.then(okFun, errorFun), 而应该总是使用p.then(okFun).catch(errorFun), 这种写法更符合同步的写法。注意Promise对象抛出的异常不会传递到外层,所有如果没有.catch(), 即使添加了try{p.then()} catch(err) {},p发生错误时也不会被catch到。

    4. Promise.all()

    接受一个由Promise实例组成的数组作为参数,同样返回一个Promise实例,相当于把多个Promise实例包装成一个新的Promise实例。如 var p = Promise.all([p1,p2,p3]),只有p1, p2, p3都是resolved,p才会是resolved,此时p1, p2, p3的返回值组成一个数组,传给p的回调函数;只要p1, p2, p3有一个rejected,p就是rejected,此时第一个被rejected的实例的返回值传给p的回调函数。

    5. Promise.race([p1, p2,p3])

    类似于Promise.all(), 区别是只要p1, p2, p3中有一个实例率先改变状态,p的状态就跟着改变。

    6. Promise.resolve()

    可以把非Promise对象转为Promise对象,如果已经是Promise对象,则原封不动的返回。

    var p = Promise.resolve('hello') 即相当于 var p = new Promise( resolve => resolve('hello')),'hello'不是异步操作,状态会立马变成resolved,立即执行回调函数;

    var p = Promise.resolve( $.ajax('/a.json') ) 即相当于 var p = new Promise( resolve => {vap rsp = $.ajax('/a.json') ;resolve(rsp); )

    也可以 var p = Promise.resolve(); p.then()

    7. Promise.reject()

    类似Promise.resolve(),var p = Promise.reject('hello') 即相当于 var p = new Promise( (resolve, reject) => reject('hello'))

    8. async, await关键字

    Promise的写法虽然比起普通回调函数的写法有很多改进,但一眼看上去,代码完全是Promise的api(.then().catch()),操作本身的语义还不是特别明显,而用async函数的写法最符合语义,没有与语义不相干的代码。

    async关键字表示该函数内部有异步操作,await 后面是一个Promise对象,执行到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句

    一个简单的例子:

    var p = () => {return new Promise( resolve => setTimeout(resolve, 5000))}
    var fun = async () => {
      console.log(1)
      await p().then(()=>console.log(2))
      console.log(3)
    }
    fun()
    console.log(4)
    
    // 运行结果
    //1
    //4
    //(5s后)2
    //3

    注意:await 只能运行在一个函数里,且只能运行在async函数里,用在普通函数里会报错。因为await表示这里需要等待,await后面的代码无法立即执行,把await放在async函数里面后,执行到await就会跳出这个函数,继续执行函数外面的代码,等await返回异步操作结果后,再继续执行这个async函数内await后面的代码。另外因为await后面的Promise对象的运行结果有可能是rejected,所有最好把await命令放在try...catch代码块中。

    一个sleep函数,暂停程序:

    const sleep = (ms) => {
      return new Promise(resolve => setTimeout(resolve, ms))
    };
    const demo1 = async() =>{
      console.log(1)
      await sleep(5000).then(() => console.log(2))
      console.log(3)
    }
    demo1();
    // demo1() 或 demo2均可以
    const demo2 = async() =>{
      console.log(1)
      await sleep(5000)
      console.log(2)
      console.log(3)
    }
    demo2();
    
    // 运行结果
    // 1
    // (5s后)2
    // 3
  • 相关阅读:
    Django-ORM和MySQL事务及三大范式介绍
    django-视图层与模板层
    django初步--+urls解析
    django前戏
    python web开发中跨域问题的解决思路
    MySQL显示ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)解决方法
    xpath
    HTTP请求方法
    JavaScript 对象
    JavaScript 关键字
  • 原文地址:https://www.cnblogs.com/yigeqi/p/6039923.html
Copyright © 2011-2022 走看看