Promise处理异步操作

Promise对象

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

我的理解:Promise使得异步的写法不像之前那样一直回调,而可以用同步的代码书写格式去写异步代码。

以一个实例开头:以下实例,产生一个随机数,比0.5大触发Promise的resolve方法,比0.5小触发Promise的reject方法。prom对象通过then方法捕获resolve和reject,通过resolve或reject触发prom.then方法中的对应的处理函数。从而实现异步事件的代码同步的写法。

let prom = new Promise(function(resolve, reject){
  let num = Math.random() - 0.5;
  setTimeout(() => {
    if(num > 0){
      resolve(num);
    }else{
      reject(num);
    }
  }, 5000);
})
console.log(prom);
console.log(prom.then(function(value){
  console.log("status is resolved");
  return "value is resolve"
},function(value){
  console.log("status is rejected");
  return "value is reject"
}))

 相关的知识点:

(1)构造函数Promise创建对象,得到的是一个Promise对象,该对象可以通过then方法来捕获resolve和reject,而返回一个新的Promise对象。

(2)new Promise的方式创建Promise对象,传入的处理函数是立即执行函数,且接收两个参数,分别是resolve和reject,resolve()执行,表明Promise对象达到完成且成功的状态,reject()执行表明Promise对象达到完成且失败的状态。

(3)resolve()和reject()两个方法可以接收参数,并将参数传给对应的then方法对应的处理函数。

(4)Promise对象包括两个值,状态:PromiseStatus、传递的值:PromiseValue。

关于返回Promise对象的状态和值:

(1)pending状态下,无返回值

得到Promise {},在创建Promise尚未到达完成状态时,都是pending状态,pending状态是没有返回值的。

所有Promise对象在then执行前都是状态。

1)new Promise等待then的执行前

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                resolve(res);
            }else{
                reject("error")
            }
            
        })
    })
    console.log(prom1);
    prom1.then(function(data){
        console.log(data);
    },function(error){
        console.log(error)
    })

2)Promise.resolve().then()

console.log(Promise.resolve().then())

3)Promise.reject().then()

console.log(Promise.reject().then())

4)Promise.all([]).then()

console.log(Promise.all([]).then())

6)Promise.race([]).then()

console.log(Promise.race([]).then())

 原因:Promise是微任务,console.log是宏任务,在执行console的时候,Promise还未执行呢,当然是pending状态。

 (2)resolved状态(fulfilled状态)

resolved状态是当Promise对象达到resolve()执行的条件时,返回的Promise对象的状态会改为resolved。与此同时对应的then方法捕获到状态的改变,执行then的处理函数。

let prom = new Promise(function(resolve, reject){
  let num = Math.random() - 0.5;
  setTimeout(() => {
    if(num > 0){
      resolve(num);
    }else{
      reject(num);
    }
  }, 5000);
})
console.log(prom);        Promise {}
setTimeout(() => {
  console.log(prom);      Promise {: 0.3569827867211466}
}, 6000);

1)那么我们在立即执行函数中,立即触发resolve()或reject(),打印出来的Promise对象也是完成的状态,

打印结果:Promise {: "success"}

console.log(new Promise(function(resolve, rejected){
  resolve("success")
}))

 2)我们直接调用Promise的resolve方法,也会得到resolved的状态:

console.log(Promise.resolve("success"))   Promise {: "success"}

特别注意:resolve()方法传入的值,即使当前Promise对象的返回值,也是传给then方法的数据。

Promise.resolve() 和 Promise.reject()方法是宏任务一样的执行,返回完成状态的Promise对象

(3)rejected状态

失败的时候的状态,和resolved状态都是完成状态。

探究then方法

then方法捕获Promise状态完成,值来自Promise对象。

(1)then的执行时机(执行顺序)

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                resolve(res);
                console.log(111);
            }else{
                reject("error")
            }
            
        })
    })
    prom1.then(function(data){
        console.log(data);
    },function(error){
        console.log(error)
    })

创建Promise对象的resolve()和reject()处理函数也是微任务。 上面代码111先执行

(2)链式调用的原理

Prom对象的PromiseValue会传递给调用的then方法,then方法处理函数return返回的结果,作为新Promise对象的PromiseValue值传递给下一个then方法。

执行顺序,两处的then对比,222比success先执行,为什么?

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                resolve(res);
                console.log(111);
                Promise.resolve("222").then(val => console.log(val))
            }else{
                reject("error")
            }
            
        })
    })
    prom1.then(function(data){
        console.log(data);
        return "success";
    },function(error){
        console.log(error)
        return "faild";
    }).then(success => console.log(success),faild => console.log(faild));

(3)值的传递

(4)catch方法关系

catch方法捕获Promise对象的reject状态;catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected)

 下面实例中,捕获prom1的reject

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                reject(res);
            }     
        })
    })
    prom1.catch(val => console.log(val))
    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                reject(res);
            }     
        })
    })
    prom1.then(function(data){
        console.log(data);
    },function(error){
        console.log(error);//捕获reject()
    })
    Promise.reject("faild").catch(val => console.log(val))

 (5)finally方法关系

不管是then方法、catch方法、还是finally方法,都是捕获调用它的Promise对象。

then方法回调函数的返回值

  • 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。有返回值——>带有该值的接收状态
  • 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined无返回值——> 值为undefined的接收状态
  • 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。错误——> 值为错误原因的拒绝状态
  • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。接收状态的Promise ——> 值为该Promise的值 接收状态
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。拒绝状态的Promise ——> 值为该Promise的值的拒绝状态
  • 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。pending状态的Promise ——> 

Promise对象的方法

(1)catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected)).

返回一个Promise对象,所以可以链式调用。

所以我们在处理reject的时候,需要在后面跟catch方法:

Promise.reject("fail").catch(function(value){
  console.log(value);
})

(2)finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。

这避免了同样的语句需要在then()catch()中各写一次的情况。

由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。

额外:

注意一个关于throw的关键字:抛出异常错误

throw new TypeError("Oops, we haven't got JSON!");
throw new Error("11");
throw Error("22")

(3)Promise.all(iterable) 方法

返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“resolved”或参数中不包含 promise回调完成

如果参数中  promise 有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise 的结果。

如果传入的iteratable对象内不包含Promise,也是返回一个Promise对象:

Promise.all([1,2,3])

Promise执行完成后的值:

Promise处理异步操作_第1张图片

它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

上面代码3秒后打印:[3, 42, "foo"]

 特别注意:

(1)上面实例中Promise.all的用法,同时setTimeout的使用。

(2)返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。

比如调整上面几个的排列顺序:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'foo');
});

Promise.all([promise3,promise1, promise2]).then((values) => {
  console.log(values);
});

打印结果:["foo", 3, 42] 

下面实例中,当两个Promise对象都resolve时,返回一个数组,长度为2,内容为两个resolve传递的值

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                resolve(res);
            }else{
                reject("prom1 reject");
            }  
        })
    })

    let prom2 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/restful/:id/list", function(res){
            if(res){
                resolve(res);
            }else{
                reject("prom2 reject");
            }  
        })
    })
    Promise.all([prom1, prom2]).then(val => console.log(val))

问:为什么打印的是数组?

答:因为Promise.all接收的是一个数组,每个数组的promise执行的结果,返回到对应promise的位置上。所以当每个Promise执行完成后,all的参数就是["foo", 3, 42] ,此时调用then方法,将其打印出来。

(4)Promise.race(iterable) 方法

返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。竞争关系,一旦有一个Promise执行结束,就返回它的执行完成状态,其他的Promise对象不再执行。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 200, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);   two
  // Both resolve, but promise2 is faster
});

如果传的迭代是空的,则返回的 promise 将永远等待。

如果传入的参数数组包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为参数数组中找到的第一个值。

传入非Promise对象或已解决或已拒绝的Promise对象:

var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.race(resolvedPromisesArray);
console.log(p);  //Promise {}

setTimeout(function(){
    console.log('the stack is now empty'); //the stack is now empty
    console.log(p);  //Promise {: 33}
});

传入值为Promise对象的iterator对象:比如值为Promise的数组

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
  // 两个都完成,但 p2 更快
});

var p3 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 500, "four"); 
});

Promise.race([p3, p4]).then(function(value) {
  console.log(value); // "three"
  // p3 更快,所以它完成了              
}, function(reason) {
  // 未被调用
});

var p5 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "five"); 
});
var p6 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 100, "six");
});

Promise.race([p5, p6]).then(function(value) {
  // 未被调用             
}, function(reason) {
  console.log(reason); // "six"
  // p6 更快,所以它失败了
});

正常的使用,传递多个异步任务,当其中一个任务结束,返回该任务的处理结果

    let prom1 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/getMovie", function(res){
            if(res){
                resolve(res);
            }else{
                reject("prom1 reject");
            }  
        })
    })

    let prom2 = new Promise(function(resolve, reject){
        $.get("https://www.easy-mock.com/mock/5b4c4032189fc57b63eb8410/example/restful/:id/list", function(res){
            if(res){
                resolve(res);
            }else{
                reject("prom2 reject");
            }  
        })
    })
    Promise.race([prom1, prom2]).then(val => console.log(val))

结果:其中一个任务的resolve()值,或reject()值

 

你可能感兴趣的:(ES6,Promise)