Promise 是 ES6 推出的另一个用于异步函数回调的构造函数.
它的使用方式大致如下.
var p = new Promise(function(reslove,reject){
if (!err) reslove(data)
reject(err)
})
p.then((data)=>{
console.log(data) // success
},(err)=>{
console.log(err)
})
一个实际的例子
function promiseGet(url) {
return new Promise(function(reslove,reject){
let xhr = new XMLHttpRequest()
xhr.onload = function(data) {
resolve(json.parse(xhr.responseText))
}
xhr.onError = function() {
reject(xhr.statusText)
}
xhr.open('GET',url,true)
xhr.send()
})
}
promiseGet('./data/users/1')
.then(
data=>{
console.log(data)
},
err=>{
console.log(err)
})
Promise 基本用法说明
我们可以将 Promise 想象成一个容器,这个容器里装一个异步操作的行为.并根据这个异步操作的返回的结果,来告知 Promise 那种是成功状态,哪一种是失败状态.
new Promise(function(resovle,reject){
$.get('./data/users/1',function(data){
if (!data.err) reslove(data.info)
reject(data.err)
})
})
容器里装的异步行为是
$.get()$.get(,callback) 告知了
Promise当data.err不存在或者为undefined的时候,是成功状态.调用reslove函数,并传入data.info$.get(,callback) 告知了
Promise当data.err存在的时候是失败状态,调用reject,并传入错误信息.
到目前为止,Promise 接受了一个 函数 作为参数.
此参数函数里,有两个回调函数.
但这些都只是形参,除了函数内部的异步操作. Promise没有拿到其他任何实质性的数据.
then又是什么?
现在,Promise有了一个异步的操作,它知道需要去执行异步操作了.
我们写代码的时候是 new Promise(function(reslove,reject){....})
传递给 Promise 构造函数的参数函数的 reslove 和 reject 的两个形参,在什么位置赋值呢?
毕竟 Promise 至少在其内部的某个位置,执行了这个 带有异步任务的函数了
// 伪代码
class Promise {
constructor(fn) {
super()
this.fn = fn // 接受到了我们传递的构造函数参数
}
someMoment() {
this.fn(reslove???,reject???)
}
}
then方法出场
我们在创建 Promise 对象的时候,传递了一个 fn .
Promise 到目前为止起码有一个 异步函数 fn.
假设我不知道 fn的两个形参如何去传的.那么,如果我没有传递这两个参数,Promise 接收到了这个没有设置实参到形参的异步回调函数时,会执行异步任务吗?
let pget = new Promise(function (reslove, reject) {
$.get('http://localhost:8000/users/1', function (data) {
console.log(data)
if (!data.err) reslove(data.info)
reject(data.err)
})
})

请求发出去了,也就说说,Promise 一旦创建,即使没有设置,或者说不知道如何设置 reslove & reject 异步请求仍会在创建 Promise 的时候,同步发出去.
但在传递的异步函数内部 没有设置 reslove & reject 实参时却没有报错?
难道是?
// reslove & reject 我压根就没传
console.log(`reslove:${reslove}`)
console.log(`reject:${reject}`)

即使,我并没有传递这两个状态对应的回调函数,在打印它们的时候,发现Promise帮我们自动传递了两个对应的function.
意义在哪呢?
对于一个函数参数,如果我们没有传递的话?
function fn(p1) {
console.log(p1) //undefined
// p1() // p1 is not function
// p1.a // Cannot read property 'a' of undefined
}
fn()
到目前为止有两个疑问:
对于一个没有设置回调处理
reslove or reject的Promise. 它直接把异步请求发出去有意义吗?为什么
Promise会在我们没有设置reslove&reject两个回调函数的时候,主动的去把它俩设置成function? 意义在哪?
这两个疑问暂且放置一边.
Promise.prototype.then 1.0
then 是 Promise 对象的实例方法.
它用来指定 初始化异步任务函数的 reslove,reject 实参.
let pget = new Promise(function (reslove, reject) {
$.get('http://localhost:8000/users/1', function (data) {
console.log(data)
// reslove & reject 我压根就没传
console.log(`reslove:${reslove}`) // function {navie code}
console.log(`reject:${reject}`) // function {navie code}
if (!data) reslove(data)
reject('出错啦!')
})
})
p.then(data=>{
console.log(data)
},err=>{
console.log(err)
})
使用 then 方法,为每一个 Promise 对象设置 reslove & reject

也就是说:
我们不设定
reslove&reject,Promise会帮我们封装两个在我们看来什么都不做的reslove&reject如果我们使用
then设定了reslove&reject,Promise就使用我们设定的这两个回调函数.所以,不管什么情况,
Promise都会需要这两个函数.没有就自己创建,有就直接用.
Promise.prototype.then 2.0
到目前为止,我们知道了
使用
new Promise创建一个Promise对象-
构造函数里需要传递一个匿名函数参数.
- 包括异步操作
reslovereject
使用
then来执行当前这个Promise在异步操作状态发生改变时的reslove&reject
Promise的 then 是可以链式调用的.

因为 then 方法返回的仍然是 Promise 类型.
then方法返回的是原来的那个 Promise对象 还是一个新的 Promise对象呢?
var p1 = pCreate('step 01')
var p2 = p1.then(data => {
console.log(data)
return 1
})
console.log(p1 instanceof Promise) // true
console.log(p2 instanceof Promise) // true
console.log(p1 === p2) //false

结论:
+ `then` 方法在执行完毕之后,确实又创建了一个 `Promise`对象
+ 每次 `then` 创建的 `Promise` 对象是不相同的.
为什么每次then指向完毕之后都是返回的一个全新的Promise而不是原来的那个Promise?
一般的链式调用里面都是利用return this来实现的.
个人理解:
这是和
Promise的特性相关的
-
Promise主要是做异步任务的. - 异步任务回来之后,就需要知道成功或者失败了.
- 当我们使用
then指定Promise成功或者失败的回调之后,这个Promise的使命就算完成了. - 异步任务不等于事件,比如按钮点击,可以重复执行.
- 当知道成功和失败之后,这个异步任务就算做完了.
- 所以,一个
then就代表了老的Promise任务完结,新的Promise准备就绪.
Promise.prototype.then 3.0
then的链式调用
function pCreate(stepName) {
return new Promise(function (reslove, reject) {
console.log('in')
setTimeout(function () {
reslove(stepName)
reject(stepName)
}, 100)
})
}
pCreate(0) // 第一个 promise -- pCreate() 返回
.then(data => { //
console.log(data)
return 1
})
.then(data => { // 第二个 promise 由上一个 then 返回
console.log(data)
return 2
})
.then(data => { // 第三个 promise 由上一个 then 返回
console.log(data)
return 3
})
.then(data => { // 第四个 promise 由上一个 then 返回
console.log(data)
})

这段
then链式调用,一共产生了4个Promise.除了第一个
Promise我们手动了使用pCreate()方法调用(输出in)之外,剩下三个由then调用的,都是系统内置的Promise创建方法.上一个
promise.then.reslove返回的数据被下一个promise.then.reslove接收到了.也就说,如果在上一个
then的reslove里有返回值,那么在这个then执行完毕并创建下一个promise同时,也会把return的这个data设置成下一个then的reslove的第一个实参.这样做的好处,就是可以把一个 promise 最终在
reslove里产生的数据传递到下一个Promise的reslove中去.
一个then干了三件事情
设置自己
promise的reslove&reject创建一个新的
promise把自己
promise的reslove&reject里的数据传递给新的promise的reslove&reject中.
then既设置了promise的reslove&reject.同时又创建了一个新的promise.接着还可以把自己的数据传递给下一个promise的reslove&reject
Promise.prototype.then 4.0
既然then的箭头函数可以传递数据到下一个then的箭头函数里 那么,如果我在then箭头函数里返回一个新的 promise 呢?
问题就变得奇怪了.
因为then会创建一个promise,我又在它的箭头函数里返回一个新的 promise.
但不管怎么说,在代码级别,这样做肯定是可以的.
毕竟then里无非是两个箭头函数,表示 reslove,reject.
函数里,我想返回什么就返回什么.
function pCreate(stepName) {
return new Promise(function (reslove, reject) {
setTimeout(function () {
reslove(stepName)
reject(stepName)
}, 1000)
})
}
pCreate('step 01')
.then(data => {
console.log(`data:${data}`)
return pCreate('step 02')
})
.then(data2 => {
console.log(data2) // step 02
console.log(data2 instance of
})
按照上一阶段的理解,上一个then.reslove里返回了 return 1,那么下一个then.reslove(data) === 1.
所以,这里的 data2 应该是 promise 对象才对.
但结果如下:

当上一个
then.reslove里返回的是一个非promise对象时,下一个then.reslove(data)就等于上一个reslove里的返回值当上一个
then.reslove里返回的一个promise对象是(return pCreate('step 02')). 下一个then.reslove(data)就不是一个promise对象了.
但我们发现,console.log(data2) 输出的是 step 02.
就等于是,第二个通过 return pCreate('step 02')直接设置 then 了一样.
pCreate('step 02')
.then(data=>{
console.log(data) // step 02
})
结论:
当上一个
then.reslove中返回的是一个promise对象时.这个
promise对象直接就用做成下一个then的函数调用者所以,下一个
then.reslove(**data**)就是上一个promise成功时调用reslove(**data**)传送的data.所以,在我们使用
console.log(data2)时 ,data2 instanceof Promise:false&data2:step 02
Promise.prototype.then 5.0
既然可以在 then.reslove里继续返回 promise.
那么,我们可以把一些有依耐性的接口使用 then 串联起来.
function pGet(url) {
return new Promise(function (reslove, reject) {
get(url, function (data) {
reslove(data)
})
})
}
function get(url, callback) {
let xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.send()
xhr.onload = function () {
callback && typeof callback === 'function' && callback(JSON.parse(xhr.responseText))
}
}
pGet('http://localhost:8000/users/1')
.then(function(data){
console.log(data)
let userInfo = data
return pGet(`http://localhost:8000/preferences/${userInfo.preferences}`)
})
.then((data)=>{
console.log(data)
let preferences = data
return pGet(`http://localhost:8000/hobbies/${preferences.hobbies}`)
})
.then(data=>{
console.log(data)
let hobbies = data
var hobbiesStr = hobbies && hobbies.values instanceof Array && hobbies.values.join(',')
document.querySelector('h1').innerText = hobbiesStr
})
