Promise对象

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

主要api:json

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

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的回调函数promise

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

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

一个简单的例子:async

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'

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

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的方法。ui

一个简单的例子:

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
相关文章
相关标签/搜索