Promise

中文为承诺,异步编程的新解决方案(旧的解决方案是回调函数),从语法上来说就是一个构造函数,用来封装异步任务,解决回调地狱的问题,封装一个异步操作,用来获取成功或者失败的结果的值

旧的解决方案实例:

变量.use((param1, param2) => {
    
}, param);

// 定时器也是回调
setInterval(() => {
    
}, 33333)

其中第一个参数就是一个回调函数

优点:

  • 支持链式操作
  • 解决了回调地狱
    • 回调地狱是指一个回调函数中嵌套着另外的异步任务
      • 不便于阅读
      • 不便于异常错误处理
  • 支持链式调用
setTimeout(() => {
    console.log("hello")
}, 1000);

基本形式为:

const p = new Promise((resolve, reject) => {
    if(成功的条件) {
        // 将状态置为成功
        resolve();
    } else {
        // 将状态置为失败
        reject();
    }
});

p.then(() => {
    console.log("成功的回调");
}, () => {
    console.log("失败的回调")
});



// 代码可以精简为:
new Promise((resolve, reject) => {
    if(成功的条件) {
        resolve();
    } else {
        // 失败
        reject();
    }
}).then(() => {
    console.log("成功的回调");
}, () => {
    console.log("失败的回调")
});
  • 当成功时调用resolve,中文为解决,失败时调用reject

  • 可以执行多个回调:

    const p = new Promise((resolve, reject) => {
        let number = Number.parseInt(Math.random() * 10);
        console.log(number);
        if (number % 2 === 0) {
            resolve(number);
            reject("失败水水水水")
        } else {
            reject("---失败了");
        }
    });
    
    p.then((n) => {
        console.log("成功的回调" + n);
    }, (n) => {
        console.log("失败的回调" + n)
    });
    
    p.then((n) => {
        console.log("第二个成功回调")
    }, reason => {
        console.log("第二个失败回调")
    })
    
    7
    失败的回调---失败了
    第二个失败回调
    
    
    7
    失败的回调---失败了
    第二个失败回调
    
    

获取结果

成功或者失败也可以将结果传进去

new Promise((resolve, reject) => {
    if(成功的条件) {
        resolve(值);
    } else {
        // 失败
        reject(值);
    }
}).then((res) => {
    console.log("成功的回调" + res);
}, (res) => {
    console.log("失败的回调" + res)
});

同时获取到执行的结果值

对象的属性状态 promiseStatus

是指实例对象中的一个属性,状态包括:

  • pendingˈpendiNG中文为待办的,初始的状态
  • resolve或者fulfilled,代表成功
  • reject,代表失败

只能由初始状态变换为成功或者失败状态,不能由成功变为失败,失败变为成功,状态只能改变一次

状态的改变

pending ->resolvepending -> rejectthrow 错误

try {
    throw "错误";
} catch (e) {
    console.log("异常" + e);
} finally {
    console.log("都会执行的")
}

对象的结果值属性 promiseResult

存储的是对象成功或者失败的结果,只能由resolve()reject()进行修改

工作流程

new Promise(参数)
new Promise(参数)
改变为成功状态
改变为成功状态
执行异步操作
执行异步操作
成功
成功
改变为失败状态
改变为失败状态
失败
失败
回调then()中的第一个方法
回调then()中的第一个方法
回调then()中的第二个方法或者catch中的方法
回调then()中的第二个方法或者catch中的方法
返回新的Promise对象
返回新的Promise对象
Text is not SVG - cannot display

new Promise(参数)中的参数的内容为(resolve, reject) => {代码...},这个参数中的代码将会同步的立即执行,异步任务在执行器中执行

then((接受的参数) =>{}, (失败的参数) => {}),两个函数类型的参数,都会返回一个Promise对象

catch((失败的参数) => {}),只能指定失败的回调,执行失败后执行

Promise.resolve(参数)

  • 如果参数为非Promise对象,那么返回的结果为成功的Promise对象
  • 如果参数为Promise对象,那么参数的结果决定了返回的结果

如果有一个失败的错误不进行处理,那么此时在控制台可以看到错误信息,程序不会继续执行

Promise.reject(参数)

  • 直接返回一个失败的参数,程序停止
  • 无论传入什么参数,都会返回一个失败的Promise

Promise.all(数组)

  • 数组中全部都是Promise对象

  • 只要有一个失败,就返回一个失败的Promise

  • 只有都成功时才会成功

  • const p1 = new Promise((resolve, reject) => {
        resolve();
    })
    const p2 = new Promise((resolve, reject) => {
        resolve();
    })
    const p3 = new Promise((resolve, reject) => {
        resolve();
    })
    const p4 = new Promise((resolve, reject) => {
        resolve();
    })
    const p5 = Promise.resolve("ok");
    console.log(Promise.all([p1, p2, p3, p4, p5]));
    

Promise.race(数组)

  • 返回新的Promise

  • 数组中第一个返回结果的Promise为最终的状态

  • race中文为赛跑

  • const p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("nb");
        }, 1000)
    })
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("nb");
        }, 5000)
    })
    const p3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("nb");
        }, 10)
    })
    const p4 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("nb");
        }, 10000)
    })
    console.log(Promise.race([p1, p2, p3, p4]));
    
  • p3率先执行,所以最终的结果为p3的结果

then((result) => {}, (reason => {}))的返回值:

  • 如果执行成功的回调,那么返回结果由第一个回调的返回值决定

  • let result = p.then((n) => {
        // 返回成功
        console.log("成功的回调" + n);
    }, (n) => {
        console.log("失败的回调" + n)
    });
    

串联任务

then后继续调用then,例如倒计时3 2 1

let count = 3;
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(count);
        count--;
        resolve();
    }, 1000)
}).then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(count);
            count--;
            resolve();
        }, 1000)
    })
}).then(() => {
    setTimeout(() => {
        console.log(count);
        count--;
    }, 1000)
})

异常穿透

使用then进行链式调用时,可以在最后指定异常回调,只需要在最后使用catch即可,中间的任何一个失败的情况都会被这个catch处理

let count = 3;
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(count);
        count--;
        resolve();
    }, 1000)
}).then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(count);
            count--;
            resolve();
        }, 1000)
    })
}).then(() => {
    setTimeout(() => {
        console.log(count);
        count--;
    }, 1000)
}).catch(e => {
    console.log("异常内容:" + e);
})

或者

new Promise((resolve, reject) => {
    console.log("1");
    resolve();
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
    throw "eeee"
}).then(() => {
    console.log(4);
}).then(() => {
    console.log(5);
}).catch(e => {
    console.log("异常为:" + e);
})

中断链

也就是把then调用链中断,需要返回一个pending状态的promisereturn new Promise((resolve, reject) => {})

new Promise((resolve, reject) => {
    console.log("1");
    resolve();
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
    // 中断
    return new Promise((resolve, reject) => {});
}).then(() => {
    console.log(4);
}).then(() => {
    console.log(5);
}).catch(e => {
    console.log("异常为:" + e);
})

async函数

返回值为Promise对象,结果由async函数执行的返回值决定

定义:

let fun = async () => {
    
}
// 或者
let fun2 = async function() {
    
}

例如:

const fun = async () => {
    return {
        username: "用户名",
        password: "密码"
    };
}

let promise = fun();
console.log(promise)


promise.then(result => {
    console.log(result)
})

输出结果:

Promise { { username: '用户名', password: '密码' } }
{ username: '用户名', password: '密码' }

如果返回的是一个Promise那么:

const fun = async () => {
    return new Promise((resolve, reject) => {
        resolve({
            username: "用户名",
            password: "密码"
        });
    })
}

let promise = fun();
console.log(promise)


promise.then(result => {
    console.log(result)
})

14行取出的内容不变:

Promise { <pending> }
{ username: '用户名', password: '密码' }

也是可以抛出异常的,catch中得到的错误内容就是抛出的内容:

const fun = async () => {
    throw {
        code: 404,
        content: "未找到资源"
    }
}

let promise = fun();
console.log(promise)


promise.then(result => {
    console.log(result)
}).catch(e => {
    console.log(`异常,状态码为:${e.code},内容为:${e.content}`);
})

结果:

异常,状态码为:404,内容为:未找到资源

await

右侧如果是promise对象,返回的值为promise成功的值

右侧如果是其他类型的值,直接返回相应的值

必须要在async函数中使用await,如果执行失败则需要通过try-catch进行处理

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({
            code: 8888,
            msg: "消息"
        })
    }, 2000)
})

let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject({
            code: 9999,
            msg: "消息2"
        })
    }, 2000)
})

const getValP = async () => {
    let obj = await p;
    console.log(obj)
}

const getValP2 = async () => {
    try {
        let obj = await p2;
        console.log(obj)
    } catch (e) {
        console.log("抛出异常:" + JSON.stringify(e));
    }

}

getValP();
getValP2();

结果:

{ code: 8888, msg: '消息' }
抛出异常:{"code":9999,"msg":"消息2"}

Q.E.D.


念念不忘,必有回响。