Promise异步编程风格

分享者: Jade
Date: 2015.05.28

Callback Hell

著名的回调地狱

$.get(provinceUrl, function(provinceList) {
  $.each(provinceList, function(province) {
    $.get(cityUrl, {province: province}, function(cityList) {
      $.each(cityList, function(city) {
        $.get(areaUrl, {city:city}, function(areaList) {
          //all data is ready, do something here
        })
      })
    })
  })
})

Promise style

getProvince(provinceUrl)
.then(getCityByProvince)
.then(getAreaByCity)
.then(handleAllData)
.catch(handleError)

Promise的含义

  • 中文语义:承诺
  • 状态列表:Pedding待定、Fulfilled完成、Rejected拒绝
  • 状态规则:
    • 状态的变化单向不可逆
    • 初始化状态:Pedding
    • Pedding => Fulfilled
    • Pedding => Rejected
  • Promise/A+规范: http://segmentfault.com/a/1190000002452115

Promise 的语法

var promise = new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'package.json', true)
    xhr.onload = function() { 
        resolve(this.responseText)
    }
    xhr.onerror = reject
    xhr.send(null)
})

promise.then(onFulfilled, onRejected)

Promise 特性之异步

承诺不会立即兑现

var promise = new Promise(function(resolve, reject) {
    console.log(0)
    resolve(1)
    console.log(2)
})
console.log(3)
promise.then(function(value) {
    console.log(value)
})
console.log(4)

Promise 特性之慷慨

除非承诺被忽略,否则承诺到天荒地老

then 方法总返回新的Promise实例

var promise0 = new Promise(function(resolve, reject) {
    resolve(0)
})
var promise1 = promise0.then(function(value) {return value})
var promise2 = promise0.then(function(value) {return value})
var promise3 = promise1.then(function(value) {return value})
console.log(promise0 === promise1, promise0 === promise2, promise0 === promise3)
console.log(promise1 === promise2, promise1 === promise3)
console.log(promise2 === promise3)

Promise 特性之传递

onFulfilled 的返回值在 onFulfilled 里传递,onRejected 的返回值在 onRejected 里传递

new Promise(function(resolve) {
    resolve(1)
}).then(function(value) {
    return value + 1
}).then(function(value) {
    return value * value
}).then(function(value) {
    console.log(value)
})

Promise 特性之嵌套

resolve权限掌握在最里层的promise对象手中

then方法返回的promise对象能插队

new Promise(function(parentResolve) {
    parentResolve(new Promise(function(childResolve) {
        setTimeout(childResolve.bind(null, '嵌套promise'), 1000)
    }))
}).then(function(value) {
    return new Promise(function(anotherResolve) {
        setTimeout(anotherResolve.bind(null, value + ' & then方法返回的promise'), 1000)
    })
}).then(function(value) {
    console.log(value)
})

Promise 的语法糖

Promise.resolve and Promise.reject and Promise.prototype.catch

Promise.resolve(1)
new Promise(function(resolve) {
    resolve(1)
})

Promise.reject(2)
new Promise(function(resolve, reject) {
    reject(2)
})

Promise.resolve(1).catch(onRejected)
Promise.resolve(1).then(undefined, onRejected)

Promise 的两个静态方法

Promise.all and Promise.race

//@promiseList {Array}
//@resultList {Array}
Promise.all(promiseList).then(function(resultList) {})

//@promiseList {Array}
//@result {*}
Promise.race(promiseList).then(function(result) {})

Thenable 对象

Promise.resolve 能将 thenabel 转化成 promise 对象

var thenable = {
    value: 1,
    then: function(onFulfilled, onRejected) {
        if (this.value) {
            onFulfilled(this.value)
        } else {
            onRejected()
        }
    }
}
Promise.resolve(thenable).then(function(value) {console.log(value)})

假承诺模式 http://code.w3ctech.com/detail/209

var thenable = {
    value: 0,
    then: function(onFulfilled) {
        console.log(this.value++)
        setTimeout(onFulfilled.bind(null, this), 1000)
    }
}
Promise.resolve(thenable).then(function(value) {
    console.log(value) //never run
})

$.ajax 的返回值是一个 thenable 对象

var fetchData = Promise.resolve($.get('a.txt')) //转化为promise对象
fetchData.then(function(result) {
    //do something
}).catch(function(error) {
    //handle error
})

jQuery 实现了一个不完备的 promise

没有传递,并不慷慨

$.get('data.txt').then(function(data){
    return $.parseJSON(data)
}).then(function(data) {
    console.log(data) //还是字符串
})

fetch('data.txt').then(JSON.parse).then(function(json) {
    cosnole.log(json) //javascript plain object
})

//jquery then 方法源码
function (a,b,c){i.done(a).fail(b).progress(c);return this}

没有嵌套

$.get('data1.txt').then(function(data1) {
    return $.get('data2.txt') //默默发出请求
}).then(function(data2) {
    //data2 === data1
})

jQuery.when !== Promise.all

var urls = ['a.txt', 'b.txt', 'c.txt', 'd.txt']

$.when.apply(null, urls.map($.get)).then(function(result1, result2, result3) {
    console.log(result1, result2, result3)
})

Promise.all(urls.map($.get)).then(function(results) {
    console.log(results) //results is Array type
})

Powered By nodePPT v1.2.2