乐趣区

关于es6:ES6的Promise对象详解

什么是 Promise?为什么要应用 Promise?

当咱们应用 js 的异步调用时通常习惯应用回调函数,这样的代码简略便于了解,然而当回调嵌套的时候就会造成代码凌乱,不好梳理,比方:

function fun1(arg1,function(){// dosomething})

这样简略的嵌套天然是没问题,还便于了解。然而当有多层嵌套的时候:
咱们只晓得 Promise 是最大的益处是为了防止“回调天堂”,就是多层的回调

function fun1(arg1,function(data1){function fun1(arg2, function(data2){function fun1(arg3, function(data3){//.....})
    })
})

像下面这样,三层嵌套就曾经很麻烦了,更何况更多层的嵌套,所以为了让回调更显著,代码更容易了解,应用 Promise 能够很优雅的解决这个问题:

var p = new Promise(function(resolve,reject){
}).then(function(data){
}).then(function(data){
}).then……

下面就是 Promise 的根本用法,Promise 承受一个回调函数,回调函数接管两个参数,resolve(将 Promise 的状态从 pending 变为 fulfilled,在异步操作胜利时调用,并将异步操作的后果传递进来)、reject(将 Promise 的状态从 pending 变为 rejected,在异步操作失败时调用,将异步操作的谬误作为参数传递进来) 这两个都是函数,示意胜利和失败的处理函数。then 中承受的是上一次回调返回的后果,所以这样的链式调用就能够齐全清晰的实现多层调用。

Promise 对象有两个特点:
①,对象的状态不受外界的影响,Promise 有三种状态:Pending(进行中)、fulfilled(已胜利)、rejected(失败),只用异步操作的后果能够决定以后是哪一种状态,其余任何操作都无奈扭转这个操作。
②. 一旦状态扭转之后就不会再扭转。任何时候都能够失去这个后果。状态变动只有两种可能:从 pending 到 fulfilled 和从 pending 到 rejected。只有扭转就曾经定型了。

Promise 的毛病:
① 一旦创立就无奈勾销,一旦新建就会立刻执行
② 如果不设置回调函数,它的外部谬误就不会反映到内部。
③ 当处于 pending 状态时,无奈判断停顿到哪一阶段(刚开始还是快实现)。

接下来讲一下 Promise 的根本语法,先看一下 Promise 打印进去的后果

从上图能够看到 Promise.prototype 上有 catch、then、constructor 办法。所以这几个办法能够被实例继承。

Promise 本身会有 Promise.all()、Promise.race()、Promise.resolve()、Promise.reject() 一些罕用的办法。

1.Promise.prototype.then()

let promise = new Promise(function(resolve,reject){console.log("promise");
        resolve();});
setTimeout(function(){console.log("setTimeout");
},0)
promise.then(function(){console.log("resolved");
})
console.log("hi");

// promise   hi   resolved  setTimeout

下面的代码很好的验证了,promise 是创立之后立刻执行,then 办法指定的脚本在以后的所有同步工作实现之后再执行,setTimeout 是在下一轮“工夫循环”开始时执行,then 在本轮事件循环完结时执行。

2.Promise.prototype.catch()
当 Promise 对象执行胜利时应用的是 resolve 回调函数,进而在 then 办法中进一步解决,当 promise 对象失败时在那儿进行解决?
有两种办法:①在 then 办法承受第二个函数参数,用来处理错误。(不举荐)
② 在 catch 中进行解决。(举荐)
先看第一种:

let promise = new Promise(function(resolve,reject){reject();
});

promise.then(function(){console.log("resolved");
},function(){console.log("rejected")
})

输入 rejected

应用 catch

let promise = new Promise(function(resolve,reject){reject();
});

promise.then(function(){console.log("resolved");
}).catch(function(){console.log("catch the reject")
})

输入 catch the reject

reject 的作用就相当于抛出谬误,catch 或者 then 的第二个函数参数进行捕捉,再 resolve 之后再抛出谬误是没有用的,因为状态一旦产生就无奈扭转。

Promise 对象的谬误具备冒泡的性质,即所有的谬误始终能够向后传递,晓得遇到 cantch 被捕捉。
留神:个别尽量不要应用 then 的第二个函数参数进行错误处理,尽量应用 catch 进行谬误的对立解决。

Promise 对象若没有指定错误处理,外部谬误不会退出过程或终止脚本执行,也就是说 promise 对象的外部谬误不会影响内部代码的执行。

let promise = new Promise(function(resolve,reject){resolve();
});

promise.then(function(){console.log("resolved");
        y+2;
})

setTimeout(function() {console.log("我呈现在 y + 2 之后")
},3000)
下面的代码,浏览器遇到 y + 2 未声明抛出谬误,然而 setTimeout 中的字符串在 3 秒后仍然能够打印进去。

看一下 Promise 对象的一些办法:
1. Promise.resolve()
我感觉介绍 Promise 的办法时应该先介绍这个办法,因为前面要用到。
不要感觉它生成的 Promise 对象的状态间接是 resolved。(视状况而定)
该办法的作用是将现有对象转化为一个 Promise 对象。
将一个对象转化为 Promise 对象分为四种状况:
① 参数是 Promise 的实例,不做任何扭转。
② 参数是一个对象,且含有 then 办法(简称 thenable 对象);

var thenable = {
        then:function(resolve,rejected){resolve(42);}
}

let p1 = Promise.resolve(thenable);
p1.then(function(data){console.log(data);//42
})

thanable 的 then 办法执行后,对象 p1 的状态就变为 resolved,立刻执行 then。
当然 Promise.resolve() 也能够生成状态为 rejected 的 promise 对象,下面只须要将 resolve 改为 reject,再在 p1.then 前面加上.catch 用于捕捉谬误就能够啦!
③ 参数不具备 then 办法,或者说基本就不是对象的时候。
var p = Promise.resolve(“Hello”);
p.then(function(s){
console.log(s);//Hello
})
返回的 promise 的实例的状态间接就是 resolved,所以会执行 then 办法。并且 Promise.resolve() 的参数会传递给回调函数。

④ 不带有任何参数,用于疾速的生成一个 Promise 对象。
var p = Promise.resolve();

2. Promise.all()
该办法承受多个 Promise 实例作为参数,返回一个新的 Promise 实例。
当所有的 Promise 实例都返回 resolve 的时候,新的 Promise 实例的状态是 fulfilled,此时 p1,p2,p3 的返回值组成一个数组传递给新实例的回调函数。当有一个返回的是 rejecte 的时候,新实例的状态就是 rejected。此时第一个返回 reject 的实例的返回值就会传递给 p 的回调函数。

promise 承受的参数都是 promise 的实例,那么怎么将所有的参数都转化为 promise 的实例呢?应用下面的 Promise.resolve() 办法。
为了更好的把握 Promise.all() 办法,来做一个例题。

怎么应用 Promise 的相干常识输入 Welcome To XIAN

var p1 = Promise.resolve("Welcome");
var p2 = "To";
var p3 = new Promise(function(resolve,reject){setTimeout(function(){resolve("XIAN");
    },1000)
})

其实这个题在我讲的这块呈现,大家都晓得要应用 Promise.all 办法,还有问题就是他的参数必须都是 Promise 的实例,p1 曾经通过 Promise.resolve 转化成了 Promise 对象,p2 咱们再应用它转换一下,p3 自身就是 Promise 对象的实例。

应用上面的代码就完满的解决了:

Promise.all([p1,Promise.resolve(p2),p3])
       .then(function(data){console.log(data instanceof Array)//true
        console.log(data.join(" "));// 转化为字符串输入

}).catch(function(e){console.log(new Error(e));
})

下面的 data 是 Promise 对象 resolve 函数的参数组成的数组。还有 all 中的程序决定了输入的程序,与其余的因素没有关系。

如果所有实例中有 catch 办法用于捕捉谬误,则应用 Promise.all 办法的 catch 是不会捕捉到的。然而会执行 Promise.all 中的 then 办法,为什么?不是说当所有实例都返回的是 resolve 状态时才会触发 Promise.all 的 then 办法么?

因为当某一个实例报错时,应用 catch 进行错误处理,返回的是一个新的 Promise 实例,该实例实现 catch 之后状态也会变为 resolve,所以导致 Promise.all 所有实例的都返回 resolve,会触发 Promise.all 的 then。
解决办法就是在实例中不增加 catch,那么实例中 reject 就会触发 Promise.all 的 catch,从而达到 Promise.all 存在的真正意义。

3.Promise.race()
与 Promise.all 一样,承受的是 promise 实例数组作为参数,新生成一个新的 Promise 对象。所以该办法的参数能够应用 Promise.resolve() 办法来解决。

该办法的 Promise 的对象由第一个返回 reject 或者 resolve 的实例的状态决定。能够应用咱们常常看到的是图片加载超时什么提醒,那么能够应用该办法实现一下。
加载图片的函数也应用 Promise 对象

function preloadImage(path){return new Promise(function(resolve,reject){var image = new Image();
        image.onload = resolve;
        image.onerror = reject;
        image.src = path;
    })
}

要实现的性能是在五秒之后如果图片加载不进去就揭示图片加载超时。

Promise.race([preloadImage("/images/1.png"),
            new Promise(function(resolve,reject){setTimeout(function() {reject();
                },5000);
    })]).then(function(){alert("图片加载胜利!")
    }).catch(function(){alert("图片加载失败!")
    })

在五秒中之内先是图片加载,(当然图片加载也有可能失败)还是在五秒后登程 setTimeout 函数执行 reject。这样能够容许图片在五秒之内实现加载给提醒。

4.Promise.reject()
看到这个就会想到 Promise.resolve(). 区别就是:
Promise.resolve() 生成的 Promise 对象能够是 rejected 状态和 resolve 状态。
Promise.reject() 只能生成状态为 rejected 的 Promise 实例。

var arg = "Hello";
var pro1 = Promise.reject(arg);

pro1.then(function(){console.log("resolved");
}).catch(function(e){console.log(e === arg)//true
    console.log(e) //Hello
})
var thenable = {then(resolve,reject){reject("出错了");
    }
}
var pro1 = Promise.reject(thenable);

pro1.then(function(){console.log("resolved");
}).catch(function(e){console.log(e === thenable) //true
    conaloe.log(e);
    //{then: ƒ}
    //then:ƒ then(resolve,reject)
    //__proto__:Object
    console.log(e instanceof Object); //true
})

能够看出 Promise.reject() 办法的参数会一成不变的作为 reject 的理由,编程后续办法的参数。 所以这里输入的 e 不是“出错了”字符串,而是传入 Promise.reject() 中的参数。 它不是像 Promise.resolve() 一样应用 resolve 或者 reject 中的参数。

退出移动版