上一节:Promise 详细说明
async 函数、await 方法是 ES7 提出的基于 Promise 的解决异步的最终方案。
注:任意一个函数都可以被声明成一个 async 函数。
async 函数内部可以添加任意语句来执行,主要目的是为了得到一个 Promise 对象的状态及结果。
函数内部返回结果主要有三种情况:
返回非 Promise 对象的数据
async function main() {
return 111;
}
let result = main();
console.log(result); // Promise {: 111}
返回 Promise 对象
返回的 Promise 对象的状态及结果值,直接影响道产生结果的 Promise 对象的状态及结果值
async function main() {
return new Promise((resolve, reject) => {
resolve("ok");
// reject("err");
});
}
let result = main();
console.log(result); // Promise {: "ok"}
抛出异常
async function main() {
throw "出错了";
// throw new Error("出错了");
}
let result = main();
console.log(result); // Promise {: '出错了'}
async 函数结合 await 表达式注意点:
await 表达式后所跟内容一般有三种情况:
await 后非 Promise 对象,该值会被直接返回
async function main() {
let rs = await 100;
console.log(rs); // 100
}
main();
await 后为成功的 Promise 对象,成功的结果值会被直接返回
async function main() {
let rs = await new Promise((resolve, reject)=>{
resolve('ok')
});
console.log(rs); // ok
// let rs = await Promise.resolve('okk');
// console.log(rs); // okk
}
main();
await 后为失败的 Promise 对象,会抛出异常,可以使用 try...catch
捕获
async function main() {
try {
// let rs = await new Promise((resolve, reject)=>{
// reject('error')
// })
let rs = await Promise.reject("error");
console.log(rs);
} catch (e) {
console.log(e); // error
}
}
main();
await 表达式执行顺序:
async function main() { console.log(1111); let result = await Promise.resolve('ok'); console.log(result); console.log(2222); console.log(3333); } main(); console.log(5555); console.log(6666); // 输出结果: // 1111 // 5555 // 6666 // ok // 2222 // 3333
结论:先同步后异步
JS 中用来存储待执行的回调函数的队列中包含了两个特定的队列:
JS 执行的时候会区分两个队列
执行顺序大致为:同步代码 -> 微队列 -> 宏队列 (同、微、宏)
setTimeout(() => {
console.log(1111);
}, 0);
new Promise((resolve, reject) => {
// reject();
resolve();
console.log(2222);
}).then((value) => {
console.log(3333);
});
console.log(4444);
// 同:2222 4444
// 微:3333
// 宏:1111
Promise 是一个构造函数,用来生成 Promise 实例
语法:new Promise(executor);
在堆内存中开辟一块空间,分配其大小以及设置地址值
堆内存:主要存储的是引用类型的数据(数组、对象、函数)
栈内存:主要存储的是基本类型的数据以及引用数据类型的地址值
Promise 构造函数是需要接收一个实际参数,该参数是一个函数(执行器函数 executor)
executor 函数接收两个参数 resolve 和 reject,分别用于将 Promise 的状态从 pending 变为 fulfilled 或 rejected
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window) {
function Promise(executor) {
executor();
}
window.Promise = Promise; // 全局添加
})(window);
new Promise((resolve, reject) => {
console.log("这是我的执行器函数",resolve,reject)
});
console.log(Promise);
__proto__
)PromiseState
(记录当前 Promise 的状态),另一个是 PromiseResult
(记录当前 Promise 的结果)只要是为构造函数的实例化对象添加属性、方法,那么直接在构造函数中 this 对象的地址引用上直接添加。
(function (window) {
function Promise(executor) {
// 为 Promise 构造函数所生成的实例化对象添加状态和结果属性
this.PromiseState = "pending";
this.PromiseResult = undefined;
executor();
}
window.Promise = Promise;
})(window);
在 executor 函数中的两个参数均为函数,这时有可能会出现 this 指向问题,this 应与[上述](#3.2 Promsie 的两个实例属性)的 this 指向相同。
修改函数中 this 指向的三种方法:call、apply、bind
语法:
函数名.call(this指向, 实参1, ...);
函数名.apply(this指向, [实参1, ...]);
call 和 apply 的区别:函数中修改完 this 指向,实际参数传递的格式不同
call 和 apply 的共同点:当 this 指向被修改完成后,函数会立即执行
call 和 bind 的区别:call 会立即执行,而 bind 不会,且只有返回值,返回的是修改后的 this 指向的新函数。
(function (window) {
function Promise(executor) {
// 为 Promise 构造函数所生成的实例化对象添加状态和结果属性
this.PromiseState = "pending";
this.PromiseResult = undefined;
executor(function () { }, function () { }); // 两个参数分别表示 resolve、reject
}
window.Promise = Promise;
})(window);
由于 executor 函数中代码重复率较高,因此需要将两个参数所对应代码进行分离
try {
executor(
function (argument) {
// console.log(this);
this.PromiseState = "fulfilled";
this.PromiseResult = argument;
}.bind(this),
function (argument) {
this.PromiseState = "rejected";
this.PromiseResult = argument;
}.bind(this)
);
} catch (err) {
this.PromiseState = "rejected";
this.PromiseResult = err;
console.error(err);
}
let p = new Promise((resolve, reject) => {
// resolve(100);
// reject("error");
throw 'error'
// throw new Error("error");
});
// 定义 resolve 和 reject 方法
let _resolve = (argument) => {
this.PromiseState = "fulfilled";
this.PromiseResult = argument;
};
let _reject = (argument) => {
this.PromiseState = "rejected";
this.PromiseResult = argument;
};
try {
executor(_resolve, _reject);
} catch (err) {
this.PromiseState = "rejected";
this.PromiseResult = err;
console.error(err);
}
箭头函数自动继承外层函数的 this 指向
let _resolve = (argument) => {
// Promise 状态为 pending 时才可以更改状态
if (this.PromiseState !== "pending") return
this.PromiseState = "fulfilled";
this.PromiseResult = argument;
};
let _reject = (argument) => {
if (this.PromiseState !== "pending") return
this.PromiseState = "rejected";
this.PromiseResult = argument;
};
then 方法接收两个参数,分别是在 Promise 成功和失败时的回调函数。
借助
Object.assign()
方法实现
function Promise(executor) { ... }
// 借助 Object.assign() 方法将 Promise 原型上的方法和属性添加到实例化对象上
Object.assign(Promise.prototype, {
// onfulfilled 成功回调函数,onrejected 失败回调函数
then(onfulfilled, onrejected) {
if (this.PromiseState === "fulfilled") {
onfulfilled(this.PromiseResult);
} else if (this.PromiseState === "rejected") {
onrejected(this.PromiseResult);
}
},
});
这两个回调函数是在 Promise 的状态改变时被调用的,这个调用是异步的,因为它依赖于 Promise 的状态变化。
Object.assign(Promise.prototype, {
// onfulfilled 成功回调函数,onrejected 失败回调函数
then(onfulfilled, onrejected) {
if (this.PromiseState === "fulfilled") {
// 使用定时器,将调用改为异步
setTimeout(() => { onfulfilled(this.PromiseResult); });
} else if (this.PromiseState === "rejected") {
setTimeout(() => { onrejected(this.PromiseResult); });
}
},
});
then 方法的[返回结果](#4.1 then 方法返回结果)是一个新的 Promise 实例化对象
新的 Promise 实例化对象的状态取决于调用 then 方法对象的状态;
如果没有返回值,则返回是一个成功的 Promise,结果值为 undefined;
如果有返回值,则需要根据返回内容进行判断:
Object.assign(Promise.prototype, {
then(onfulfilled, onrejected) {
// 调用 then 方法,返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
if (this.PromiseState === "fulfilled") {
setTimeout(() => {
try {
const value = onfulfilled(this.PromiseResult);
// 判断 value 是否为 Promise 对象
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
// 不是 Promise 对象,直接调用 resolve 方法
resolve(value);
}
} catch (e) {
// 如果有异常,则调用 reject 方法
reject(e);
}
});
} else if (this.PromiseState === "rejected") {
setTimeout(() => {
try {
const value = onrejected(this.PromiseResult);
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
} catch (e) {
reject(e);
}
});
}
});
},
});
Object.assign(Promise.prototype, {
then(onfulfilled, onrejected) {
// 调用 then 方法,返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
// 封装函数
let _common = (callback) => {
setTimeout(() => {
try {
const value = callback(this.PromiseResult);
// 判断 value 是否为 Promise 对象
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
// 不是 Promise 对象,直接调用 resolve 方法
resolve(value);
}
} catch (e) {
// 如果有异常,则调用 reject 方法
reject(e);
}
});
};
if (this.PromiseState === "fulfilled") {
_common(onfulfilled);
} else if (this.PromiseState === "rejected") {
_common(onrejected);
}
});
},
});
value => value
;reason => { throw reason }
。Object.assign(Promise.prototype, {
then(onfulfilled, onrejected) {
// 如果 onfulfilled 不是函数,则将其设置为默认值,即返回 Promise 对象的结果
if (!(onfulfilled instanceof Function)) {
onfulfilled = (value) => value;
}
if (!(onrejected instanceof Function)) {
onrejected = (reason) => { throw reason };
}
// 调用 then 方法,返回一个新的 Promise 对象
return new Promise((resolve, reject) => { ... });
},
});
let p1 = new Promise((resolve, reject) => {
resolve(100);
// reject('error');
});
let p2 = p1.then();
console.log(p2);
如果 executor 执行器函数中执行的是异步程序,则将 then 方法的回调函数存入 callbacks 对象中,等待状态改变时执行对应的回调函数。
function Promise(executor) {
// ...
this.callbacks = {}; // 存放成功和失败对应的回调函数
let _resolve = (argument) => {
// ...
if (this.callbacks.onfulfilled) {
this.callbacks.onfulfilled(argument);
}
};
let _reject = (argument) => {
// ...
if (this.callbacks.onrejected) {
this.callbacks.onrejected(argument);
}
};
// ...
}
Object.assign(Promise.prototype, {
then(onfulfilled, onrejected) {
// ...
return new Promise((resolve, reject) => {
let _common = (callback) => { ... };
if (this.PromiseState === "fulfilled") {
_common(onfulfilled);
} else if (this.PromiseState === "rejected") {
_common(onrejected);
} else {
// 异步程序处理
this.callbacks = {
onfulfilled: _common.bind(this, onfulfilled),
onrejected: _common.bind(this, onrejected),
};
}
});
},
});
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(100) }, 1000);
});
p1.then(
(value) => { console.log("成功1", value); },
(reason) => { console.log("失败1", reason); }
);
p1.then(
(value) => { console.log("成功2", value); },
(reason) => { console.log("失败2", reason); }
);
p1.then(
(value) => { console.log("成功3", value); },
(reason) => { console.log("失败3", reason); }
);
// ...
console.log(p1);
解决方案:将存储成功和失败的参数 callbacks 改为数组类型的数据。
function Promise(executor) {
// ...
this.callbacks = []; // 存放成功和失败对应的回调函数
// 定义 resolve 和 reject 方法
let _resolve = (argument) => {
// ...
// 调用成功回调函数
this.callbacks.forEach((callback) => {
callback.onfulfilled(argument);
});
};
let _reject = (argument) => {
// ...
this.callbacks.forEach((callback) => {
callback.onrejected(argument);
});
};
// ...
}
Object.assign(Promise.prototype, {
then(onfulfilled, onrejected) {
// ...
return new Promise((resolve, reject) => {
let _common = (callback) => { };
if (this.PromiseState === "fulfilled") {
_common(onfulfilled);
} else if (this.PromiseState === "rejected") {
_common(onrejected);
} else {
// 异步程序处理
this.callbacks.push({
onfulfilled: _common.bind(this, onfulfilled),
onrejected: _common.bind(this, onrejected),
});
}
});
},
});
catch 方法是 then 方法的语法糖,用于处理 Promise 对象状态为 rejected 时调用的回调函数,与 then(null, onrejected)
等效。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(100);
reject("error");
});
});
let p2 = p1.catch((err) => {
// console.log(err);
// return err
return new Promise((resolve, reject) => {
resolve("okkk");
// reject("errorrr");
});
// throw "异常";
});
console.log(p2);
Object.assign(Promise.prototype, {
// onfulfilled 成功回调函数,onrejected 失败回调函数
then(onfulfilled, onrejected) { },
catch(onrejected) {
return this.then(null, onrejected); // 直接调用 then 方法即可
},
});
在之前已经规定了 then 方法的返回值,因此无需任何的修改。
then 方法返回值
返回一个空的 Promise 对象,then 方法返回值
上面三个问题,都已经在规定 then 方法返回值时解决。
Promise.resolve()
方法可以进行传参,参数说明:
let p1 = Promise.resolve(1);
console.log(p1); // Promise {: 1}
let p2 = Promise.resolve(new Promise((resolve, reject) => { resolve(2); }));
console.log(p2); // Promise {: 2}
let p3 = Promise.resolve(new Promise((resolve, reject) => { reject("err"); }));
console.log(p3); // Promise {: "err"}
(function (window) {
function Promise(executor) { }
Object.assign(Promise.prototype, { });
// Promise 构造函数中添加方法
Promise.resolve = function (value) {
// 如果 value 已经是 Promise 对象,则直接返回 value
if (value instanceof Promise) {
return value;
} else {
// 否则,返回一个新的 Promise 对象,状态为 fulfilled,结果为 value
return new Promise((resolve) => { resolve(value); });
}
};
// 全局添加 Promise
window.Promise = Promise;
})(window);
Promise.reject()
方法不受参数影响,始终得到一个失败的 Promise 对象,并将参数作为该 Promise 对象的 PromiseResult 的值。
let p1 = Promise.reject(1);
console.log(p1); // Promise {: 1}
let p2 = Promise.reject(new Promise((resolve, reject) => { resolve(2); }));
console.log(p2); // Promise {: Promise} 里面嵌套的 Promise 是成功的
let p3 = Promise.reject(new Promise((resolve, reject) => { reject("err"); }));
console.log(p3); // Promise {: Promise} 里面嵌套的 Promise 是失败的
(function (window) {
// ...
// Promise 构造函数中添加方法
Promise.resolve = function (value) { };
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
};
// 全局添加 Promise
window.Promise = Promise;
})(window);
Promise.all()
方法需要传递一个数组参数,数组中的元素都是 Promise 对象,返回结果是一个新的 Promise 对象。
let p1 = new Promise((resolve, reject) => { resolve(100); });
let p2 = new Promise((resolve, reject) => {
resolve(200);
// reject(200);
});
let p3 = new Promise((resolve, reject) => {
resolve(300);
// reject(300);
});
const pArr = Promise.all([p1, p2, p3]);
console.log(pArr);
(function (window) {
// ...
// Promise 构造函数中添加方法
Promise.resolve = function (value) { };
Promise.reject = function (reason) { };
Promise.all = function (PromiseArr) {
let count = 0; // 定义一个计数器,统计成功的 Promise 个数
// 定义一个数组,用于存放 Promise 对象
let successArr = new Array(PromiseArr.length);
return new Promise((resolve, reject) => {
PromiseArr.forEach((item, i) => {
item.then(
(value) => {
count++;
successArr[i] = value;
// 如果计数器等于 Promise 数组的长度,则证明所有的 Promise 均成功
if (count === PromiseArr.length) { resolve(successArr); }
},
(reason) => { reject(reason); }
);
});
});
};
// 全局添加 Promise
window.Promise = Promise;
})(window);
Promise.race()
方法需要传入一个 promise 数组,该方法返回一个promise对象,数组中的 Promise 谁先完成状态的改变,就以该 Promise 的状态和结果为最终状态和结果。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(100); }, 50);
});
let p2 = new Promise((resolve, reject) => { reject(200); });
let p3 = new Promise((resolve, reject) => { resolve(300); });
const pArr = Promise.race([p3, p2, p1]);
console.log(pArr);
(function (window) {
// ...
// Promise 构造函数中添加方法
Promise.resolve = function (value) { };
Promise.reject = function (reason) { };
Promise.all = function (PromiseArr) { };
Promise.race = function (PromiseArr) {
return new Promise((resolve, reject) => {
PromiseArr.forEach(item => {
item.then(resolve, reject)
})
})
};
// 全局添加 Promise
window.Promise = Promise;
})(window);