异步编程
2020-04-16 11:10:15 0 举报
AI智能生成
前端异步编程(promise->async/await)
作者其他创作
大纲/内容
generator 函数
特点是可以暂停
两个关键词
*
yield
示例
function* read(){
yield 1;
yield 2;
yield 3;
}
let it=read()
console.log(it.next())
yield 1;
yield 2;
yield 3;
}
let it=read()
console.log(it.next())
应用
生成迭代器
Array.from vs [...likeArray]
展开运算符需要 likeArray 对象中实现迭代器
不使用 generator
let obj = {
0: 1,
1: 2,
length: 2,
[Symbol.iterator]() {
let index = 0;
return {
next() {
return {
value: this[index],
done:this.length===index++
};
}
};
},
};
0: 1,
1: 2,
length: 2,
[Symbol.iterator]() {
let index = 0;
return {
next() {
return {
value: this[index],
done:this.length===index++
};
}
};
},
};
使用 generator
let obj = {
0: 1,
1: 2,
length: 2,
// generator 可以生成 iterator
*[Symbol.iterator]() {
for(let i=0;i<this.length;i++){
yield this[i]
}
}
};
0: 1,
1: 2,
length: 2,
// generator 可以生成 iterator
*[Symbol.iterator]() {
for(let i=0;i<this.length;i++){
yield this[i]
}
}
};
iterator.next() 传参
function* read() {
let a = yield "hello";
console.log(a);
let b = yield "world";
console.log(b);
}
let it = read();
console.log(it.next()); // 第一次 next 方法传递的参数没有任何意义
console.log(it.next(1)); // 会传递给上一次 yield 的返回值
console.log(it.next(2));
let a = yield "hello";
console.log(a);
let b = yield "world";
console.log(b);
}
let it = read();
console.log(it.next()); // 第一次 next 方法传递的参数没有任何意义
console.log(it.next(1)); // 会传递给上一次 yield 的返回值
console.log(it.next(2));
co 库
function co(it) {
return new Promise((resolve,reject)=>{
function next(data) {
let {
value,done
}=it.next(data)
if(!done){
Promise.resolve(value).then(data=>{
next(data)
},reject)
}else{
resolve(data)
}
}
next()
})
}
return new Promise((resolve,reject)=>{
function next(data) {
let {
value,done
}=it.next(data)
if(!done){
Promise.resolve(value).then(data=>{
next(data)
},reject)
}else{
resolve(data)
}
}
next()
})
}
async + await
async function
async function 用来定义一个返回 AsyncFunction 对象的异步函数。
异步函数是指通过事件循环异步执行的函数,它会返回一个隐式的 Promise 作为结果。
但它的语法和结构会更像是标准的同步函数。
你还可以使用 异步函数表达式 来定义异步函数。
异步函数是指通过事件循环异步执行的函数,它会返回一个隐式的 Promise 作为结果。
但它的语法和结构会更像是标准的同步函数。
你还可以使用 异步函数表达式 来定义异步函数。
语法
async function name([param[, param[, ... param]]]) { statements }
返回值
返回一个 Promise,它将会用异步函数的返回值来 resolved,
或者用异步函数内部没有捕捉到的错误来 rejected。
或者用异步函数内部没有捕捉到的错误来 rejected。
描述
异步函数可以包含await指令,该指令会暂停异步函数的执行,并等待 Promise 的 resolution,
然后继续执行异步函数,并返回结果。
记住,await 关键字只在异步函数内有效。如果你在异步函数外使用它,会抛出语法错误。
注意,当异步函数暂停时,调用它的函数会继续执行(收到异步函数返回的隐式Promise)
async/await的目的是简化同时使用多个 promise,并对一组 Promises执行某些操作。
正如Promises类似于结构化回调,async/await更像结合了 generators 和 promises 。
然后继续执行异步函数,并返回结果。
记住,await 关键字只在异步函数内有效。如果你在异步函数外使用它,会抛出语法错误。
注意,当异步函数暂停时,调用它的函数会继续执行(收到异步函数返回的隐式Promise)
async/await的目的是简化同时使用多个 promise,并对一组 Promises执行某些操作。
正如Promises类似于结构化回调,async/await更像结合了 generators 和 promises 。
async/await vs Promise.then
and error handling
and error handling
大多数异步函数也可以使用Promises编写。但是,async 函数更容易捕获异常错误。
上面例子中的 concurrentStart 函数和 concurrentPromise 函数在功能上都是等效的。
在concurrentStart函数中,如果任一 await 调用失败,它将自动捕获异常,异步函数执行中断,
并通过隐式返回 Promise 将错误传递给调用者。
在 Promise 例子中这种情况同样会发生,该函数必须返回一个捕获函数完成的 Promise。
在 concurrentPromise 函数中,这意味着它从 Promise.all([]).then() 返回一个 Promise。
事实上,此示例的先前版本忘记了这样做!
在concurrentStart函数中,如果任一 await 调用失败,它将自动捕获异常,异步函数执行中断,
并通过隐式返回 Promise 将错误传递给调用者。
在 Promise 例子中这种情况同样会发生,该函数必须返回一个捕获函数完成的 Promise。
在 concurrentPromise 函数中,这意味着它从 Promise.all([]).then() 返回一个 Promise。
事实上,此示例的先前版本忘记了这样做!
async function concurrentStart() {
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds() // starts timer immediately
const fast = resolveAfter1Second() // starts timer immediately
// step1. Execution gets here almost instantly
console.log(await slow) // step2. this runs 2 seconds after step1.
console.log(await fast)
// step3 this runs 2 seconds after step1 ,
// immediately after step2 , since fast is already resolved
}
function concurrentPromise() {
console.log('==CONCURRENT START with Promise.all==')
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]) // slow
console.log(messages[1]) // fast
})
}
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds() // starts timer immediately
const fast = resolveAfter1Second() // starts timer immediately
// step1. Execution gets here almost instantly
console.log(await slow) // step2. this runs 2 seconds after step1.
console.log(await fast)
// step3 this runs 2 seconds after step1 ,
// immediately after step2 , since fast is already resolved
}
function concurrentPromise() {
console.log('==CONCURRENT START with Promise.all==')
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]) // slow
console.log(messages[1]) // fast
})
}
但是,async 函数仍有可能错误地忽略错误。
以 parallel 异步函数为例。
如果它没有 await(或 return )Promise.all([]) 调用的结果,则不会传播任何错误。
虽然 parallelPromise 示例看起来很简单,但它根本没有处理错误!
处理错误需要一个类似的 return Promise.all([]) 。
以 parallel 异步函数为例。
如果它没有 await(或 return )Promise.all([]) 调用的结果,则不会传播任何错误。
虽然 parallelPromise 示例看起来很简单,但它根本没有处理错误!
处理错误需要一个类似的 return Promise.all([]) 。
async function parallel() {
console.log('==PARALLEL with await Promise.all==')
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
])
}
// This function does not handle errors. See warning below!
function parallelPromise() {
console.log('==PARALLEL with Promise.then==')
resolveAfter2Seconds().then((message)=>console.log(message))
resolveAfter1Second().then((message)=>console.log(message))
}
console.log('==PARALLEL with await Promise.all==')
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
])
}
// This function does not handle errors. See warning below!
function parallelPromise() {
console.log('==PARALLEL with Promise.then==')
resolveAfter2Seconds().then((message)=>console.log(message))
resolveAfter1Second().then((message)=>console.log(message))
}
The return value of an async function is implicitly wrapped in Promise.resolve.
return foo; vs return await foo;
`return foo;` immediately returns foo and never throws, even if foo is a Promise that rejects.
`return await foo;` will wait for foo to resolve or reject if it's a Promise, and throws before returning if it rejects.
`return await foo;` will wait for foo to resolve or reject if it's a Promise, and throws before returning if it rejects.
`return foo;` immediately returns foo and never throws, even if foo is a Promise that rejects.
`return await foo;` will wait for foo to resolve or reject if it's a Promise, and throws before returning if it rejects.
`return await foo;` will wait for foo to resolve or reject if it's a Promise, and throws before returning if it rejects.
await 操作符
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
语法
[rv] = await expression;
expression
A Promise or any value to wait for.
rv
Returns the fulfilled value of the promise,
or the value itself if it's not a Promise.
rv will be undefined if the promise is rejected
expression
A Promise or any value to wait for.
rv
Returns the fulfilled value of the promise,
or the value itself if it's not a Promise.
rv will be undefined if the promise is rejected
var z;
async function f4() {
z = await Promise.reject(30);
// z = await Promise.resolve(30);
}
f4();
setTimeout(() => {
console.log(z) // undefined
}, 1000);
async function f4() {
z = await Promise.reject(30);
// z = await Promise.resolve(30);
}
f4();
setTimeout(() => {
console.log(z) // undefined
}, 1000);
描述
await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。
若 Promise 正常处理(fulfilled),其回调的 resolve 函数参数作为 await 表达式的值,继续执行 async function。
若 Promise rejected,await 表达式会把 Promise 的异常原因抛出。
如果 await 操作符后的表达式的值不是一个 Promise,它会被转化成一个 resolved Promise.
若 Promise 正常处理(fulfilled),其回调的 resolve 函数参数作为 await 表达式的值,继续执行 async function。
若 Promise rejected,await 表达式会把 Promise 的异常原因抛出。
如果 await 操作符后的表达式的值不是一个 Promise,它会被转化成一个 resolved Promise.
An await can split execution flow,
allowing the caller of the await's function to resume(继续)execution
before the deferred continuation of the await's function.
After the await defers the continuation of its function,
if this is the first await executed by the function,
immediate execution also continues
by returning to the function's caller a pending Promise for the completion of the await's function
and resuming execution of that caller.
allowing the caller of the await's function to resume(继续)execution
before the deferred continuation of the await's function.
After the await defers the continuation of its function,
if this is the first await executed by the function,
immediate execution also continues
by returning to the function's caller a pending Promise for the completion of the await's function
and resuming execution of that caller.
function resolveAfter2Seconds(x) {
// return new Promise(resolve => {
// setTimeout(() => {
// resolve(x);
// }, 2000);
// });
return x;
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
let p = f1();
console.log(p);
console.log(77);
// return new Promise(resolve => {
// setTimeout(() => {
// resolve(x);
// }, 2000);
// });
return x;
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
let p = f1();
console.log(p);
console.log(77);
控制台输出:
Promise {<pending>}
77
10
Promise {<pending>}
77
10
技术准备
高阶函数
定义
函数的参数是一个函数
函数返回了一个函数
常见应用
装饰者模式
AOP 面向切片编程中的一些例子
Aspect Oriented
Programming
AOP 面向切片编程中的一些例子
Aspect Oriented
Programming
调用多少次后让回调函数执行
function after(times, callback) {
return function() {
if (--times === 0) { callback(); }
}
};
let fn = after(3, function() {
console.log("real");
});
fn();
fn();
fn();
return function() {
if (--times === 0) { callback(); }
}
};
let fn = after(3, function() {
console.log("real");
});
fn();
fn();
fn();
发展史
callback -> promise -> generator -> async + await
Promise
使用 Promise
链式调用
then() 函数会返回一个全新的 Promise,和原来的不同
⚠️注意:一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果
使用 Promise 时的约定(规范)
- 传递到 then() 中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在 本轮 Javascript event loop(事件循环)运行完成 之后调用的
- 通过 then() 添加的回调函数总会被调用,即便它是在异步操作完成之后才被添加的函数。
- 通过多次调用 then(),可以添加多个回调函数,它们会按照插入顺序一个接一个独立执行。
错误传递
一旦异常抛出,浏览器就会查找链中的 .catch() 处理器或者 onRejected
Promise 拒绝事件
当 Promise 被拒绝时,会有下文所述的两个事件之一被派发到全局作用域。
这两个事件如下所示:
rejectionhandled
当 Promise 被拒绝、并且在 reject 函数处理该 rejection 之后会派发此事件。
unhandledrejection
当 Promise 被拒绝,但没有提供 reject 函数来处理该 rejection 时,会派发此事件。
这两个事件如下所示:
rejectionhandled
当 Promise 被拒绝、并且在 reject 函数处理该 rejection 之后会派发此事件。
unhandledrejection
当 Promise 被拒绝,但没有提供 reject 函数来处理该 rejection 时,会派发此事件。
PromiseRejectionEvent 的两个属性
- promise 属性,该属性指向被驳回的 Promise
- reason 属性,该属性用来说明 Promise 被驳回的原因
我们可以通过以上事件为 Promise 失败时提供补偿处理,也有利于调试 Promise 相关的问题。
在每一个上下文中,该处理都是全局的,因此不管源码如何,所有的错误都会在同一个handler中被捕捉处理。
一个特别有用的例子:当你使用 Node.js 时,有些依赖模块可能会有未被处理的 rejected promises,这些都会在运行时打印到控制台。
你可以在自己的代码中捕捉这些信息,然后添加与 unhandledrejection 相应的 handler 来做分析和处理,或只是为了让你的输出更整洁。
举例如下:
window.addEventListener("unhandledrejection", event => {
/* 你可以在这里添加一些代码,以便检查
event.promise 中的 promise 和
event.reason 中的 rejection 原因 */
event.preventDefault();
}, false);
调用 event 的 preventDefault() 方法是为了告诉 JavaScript 引擎当 promise 被拒绝时不要执行默认操作,
默认操作一般会包含把错误打印到控制台。
理想情况下,在忽略这些事件之前,我们应该检查所有被拒绝的 Promise,来确认这不是代码中的 bug。
在每一个上下文中,该处理都是全局的,因此不管源码如何,所有的错误都会在同一个handler中被捕捉处理。
一个特别有用的例子:当你使用 Node.js 时,有些依赖模块可能会有未被处理的 rejected promises,这些都会在运行时打印到控制台。
你可以在自己的代码中捕捉这些信息,然后添加与 unhandledrejection 相应的 handler 来做分析和处理,或只是为了让你的输出更整洁。
举例如下:
window.addEventListener("unhandledrejection", event => {
/* 你可以在这里添加一些代码,以便检查
event.promise 中的 promise 和
event.reason 中的 rejection 原因 */
event.preventDefault();
}, false);
调用 event 的 preventDefault() 方法是为了告诉 JavaScript 引擎当 promise 被拒绝时不要执行默认操作,
默认操作一般会包含把错误打印到控制台。
理想情况下,在忽略这些事件之前,我们应该检查所有被拒绝的 Promise,来确认这不是代码中的 bug。
组合
Promise.resolve() 和 Promise.reject() 是手动创建一个已经 resolve 或者 reject 的 Promise 快捷方法。
它们有时很有用。
Promise.all() 和 Promise.race() 是并行运行异步操作的两个组合式工具。
它们有时很有用。
Promise.all() 和 Promise.race() 是并行运行异步操作的两个组合式工具。
嵌套
嵌套 Promise 是一种可以限制 catch 语句的作用域的控制结构写法。
明确来说,嵌套的 catch 仅捕捉在其之前同时还必须是其作用域的 failureres,而捕捉不到其嵌套域以外的 error。
如果使用正确,那么可以实现高精度的错误修复。
明确来说,嵌套的 catch 仅捕捉在其之前同时还必须是其作用域的 failureres,而捕捉不到其嵌套域以外的 error。
如果使用正确,那么可以实现高精度的错误修复。
doSomethingCritical()
.then(result => doSomethingOptional()
.then(optionalResult => doSomethingExtraNice(optionalResult))
.catch(e => {})) // Ignore if optional stuff fails; proceed.
.then(() => moreCriticalStuff())
.catch(e => console.log("Critical failure: " + e.message));// 没有输出
⚠️ 注意:如果 doSomethingCritical() 失败,这个错误仅会被最后的(外部)catch 语句捕获到。
.then(result => doSomethingOptional()
.then(optionalResult => doSomethingExtraNice(optionalResult))
.catch(e => {})) // Ignore if optional stuff fails; proceed.
.then(() => moreCriticalStuff())
.catch(e => console.log("Critical failure: " + e.message));// 没有输出
⚠️ 注意:如果 doSomethingCritical() 失败,这个错误仅会被最后的(外部)catch 语句捕获到。
常见错误
// 错误示例,包含 3 个问题!
doSomething().then(function(result) {
doSomethingElse(result) // 没有返回 Promise 以及没有必要的嵌套 Promise
.then(newResult => doThirdThing(newResult));
}).then(() => doFourthThing());
// 最后,是没有使用 catch 终止 Promise 调用链,可能导致没有捕获的异常
doSomething().then(function(result) {
doSomethingElse(result) // 没有返回 Promise 以及没有必要的嵌套 Promise
.then(newResult => doThirdThing(newResult));
}).then(() => doFourthThing());
// 最后,是没有使用 catch 终止 Promise 调用链,可能导致没有捕获的异常
第一个错误是没有正确地将事物相连接。当我们创建新 Promise 但忘记返回它时,会发生这种情况。
这种情况下,链条被打破,或者说,我们有两个独立的链条竞争。
这意味着 doFourthThing() 不会等待 doSomethingElse() 与 doThirdThing() 完成,将与它们并行运行。
单独的链有单独的错误处理,导致未捕获的错误。
这种情况下,链条被打破,或者说,我们有两个独立的链条竞争。
这意味着 doFourthThing() 不会等待 doSomethingElse() 与 doThirdThing() 完成,将与它们并行运行。
单独的链有单独的错误处理,导致未捕获的错误。
第二个错误是不必要地嵌套,导致了第一个错误。
嵌套还限制了内部错误处理程序的范围,如果是非预期的,可能会导致未捕获的错误。
嵌套还限制了内部错误处理程序的范围,如果是非预期的,可能会导致未捕获的错误。
第三个错误是忘记用 catch 终止链。未终止的 promise 链会导致未被捕捉的 promise rejections。
Promise
Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.
语法
new Promise( function(resolve, reject) {...} /* executor */ );
参数
executor
1. executor是带有 resolve 和 reject 两个参数的函数 。
2. Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor
(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。
3. resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
4. executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。
5. 如果在executor函数中抛出一个错误,那么该promise 状态为rejected。
6. executor函数的返回值被忽略。
2. Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor
(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。
3. resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
4. executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。
5. 如果在executor函数中抛出一个错误,那么该promise 状态为rejected。
6. executor函数的返回值被忽略。
描述
Promise 对象是一个代理对象,被代理的值在Promise对象创建时可能是未知的。
它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。
这让异步方法可以像同步方法那样返回值:不是立即返回最终执行结果,而是返回一个promise对象,其在未来某个时候能够提供值
它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。
这让异步方法可以像同步方法那样返回值:不是立即返回最终执行结果,而是返回一个promise对象,其在未来某个时候能够提供值
Promise 的三种状态
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。
当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用
(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。
当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法,
所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用
(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。
当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法,
所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
方法
1. Promise.all(iterable)
Promise.all(iterable) 方法返回一个 Promise 实例,
此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);
如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);
如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
语法
参数
iterable
一个可迭代对象,如 Array 或 String
返回值
- 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise。
- 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。注意:Google Chrome 58 在这种情况下返回一个已完成(already resolved)状态的 Promise。
- 其它情况下返回一个处理中(pending)的Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。 返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
手写 MyPromise.all(iterable)
MyPromise.all = function(values) {
// 1. 要返回一个新的 Promise 实例
return new MyPromise((resolve, reject) => {
let arr = [];
// 使用计数器解决多个异步的并发问题
let count = 0;
// 2. 返回值按照参数内的 promise 顺序排列
function processData(key, value) {
arr[key] = value;
count++;
// 3. 不能直接判断 arr.length 与 values.length 是否相等
// 因为可能会给 arr 后面的项目先赋值,这样前面异步的项目会变为 <empty>,
// 这时虽然前面有异步结果没有返回,但是 arr.length 可能就已经和 values.length 相同了
if (count === values.length) {
resolve(arr);
}
}
for (let i = 0; i < values.length; i++) {
const current = values[i];
// 4. 利用 Promise.resolve 方法返回一个以给定值解析后的Promise 对象
MyPromise.resolve(current).then(data => {
processData(i, data);
}, (err)=>{
reject(err)
});
}
});
};
// 1. 要返回一个新的 Promise 实例
return new MyPromise((resolve, reject) => {
let arr = [];
// 使用计数器解决多个异步的并发问题
let count = 0;
// 2. 返回值按照参数内的 promise 顺序排列
function processData(key, value) {
arr[key] = value;
count++;
// 3. 不能直接判断 arr.length 与 values.length 是否相等
// 因为可能会给 arr 后面的项目先赋值,这样前面异步的项目会变为 <empty>,
// 这时虽然前面有异步结果没有返回,但是 arr.length 可能就已经和 values.length 相同了
if (count === values.length) {
resolve(arr);
}
}
for (let i = 0; i < values.length; i++) {
const current = values[i];
// 4. 利用 Promise.resolve 方法返回一个以给定值解析后的Promise 对象
MyPromise.resolve(current).then(data => {
processData(i, data);
}, (err)=>{
reject(err)
});
}
});
};
2. Promise.allSettled(iterable)
3. Promise.race(iterable)
4. Promise.reject(reason)
5. Promise.resolve(value)
Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象。
此函数将类promise对象的多层嵌套展平。
- 如果该值为promise,返回这个promise;
- 如果这个值是thenable(即带有"then" 方法)),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
- 否则返回的promise将以此值完成。
此函数将类promise对象的多层嵌套展平。
Promise 原型
方法
Promise.prototype.catch(onRejected)
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.finally(onFinally)
手写 Promise
优缺点
优点
可以解答异步嵌套问题
解决多个异步并发问题 (指的是 all race 这些方法吗?)
缺点
基于回调 (基于回调有啥缺点呢??)
无法终止异步
规范
promiseaplus
特点
三个状态
等待(默认)
成功
一旦成功了就不能失败,反过来也一样
let promise = new Promise((resolve, reject) => {
reject("reject");
resolve("resolve"); // resolve 不会执行
}).then((data)=>{...},(err)=>{...});
reject("reject");
resolve("resolve"); // resolve 不会执行
}).then((data)=>{...},(err)=>{...});
如果 new Promise 的时候报错,会变成失败态,后面的 resolve 函数也不会走
失败
Promise 实例都有 then 方法
实现 Promise 类
自己实现某个功能的步骤
写出此功能的核心用法与特点,即写出测试用例
根据其核心用法与特点来实现
代码地址: /Users/lucy/code/github/FE-blog/interview/js/promise.js
方法
Promise.prototype.then()
then() 方法返回一个 Promise。它有两个参数:Promise 的成功和失败情况的回调函数。
return value
Once a Promise is fulfilled or rejected, the respective handler function (onFulfilled or onRejected) will be called asynchronously (scheduled in the current thread loop). The behaviour of the handler function follows a specific set of rules. If a handler function:
- returns a value, the promise returned by then gets resolved with the returned value as its value.
- doesn't return anything, the promise returned by then gets resolved with an undefined value.
- throws an error, the promise returned by then gets rejected with the thrown error as its value.
- returns an already fulfilled promise, the promise returned by then gets fulfilled with that promise's value as its value.
- returns an already rejected promise, the promise returned by then gets rejected with that promise's value as its value.
- returns another pending promise object, the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the resolved value of the promise returned by then will be the same as the resolved value of the promise returned by the handler.
描述
As the then and Promise.prototype.catch() methods return promises, they can be chained — an operation called composition.
示例
chaining
When a value is simply returned from within a then handler,
it will effectively return Promise.resolve(<value returned by whichever handler was called>).
var p2 = new Promise(function(resolve, reject) {
resolve(1);
});
p2.then(function(value) {
console.log("a: " + value); // 1
return value + 1;
}).then(function(value) {
console.log("b: " + value + " - A synchronous value works");
});
p2.then(function(value) {
console.log('c: '+ value); // 1
});
顺序:
a
c
b
it will effectively return Promise.resolve(<value returned by whichever handler was called>).
var p2 = new Promise(function(resolve, reject) {
resolve(1);
});
p2.then(function(value) {
console.log("a: " + value); // 1
return value + 1;
}).then(function(value) {
console.log("b: " + value + " - A synchronous value works");
});
p2.then(function(value) {
console.log('c: '+ value); // 1
});
顺序:
a
c
b
限制 promise 并发
// 理解成有几个业务窗口,以及一队排队等待办理业务的客户
function limitPromise(n = 3, pArr) {
for (let i = 0; i < n; i++) {
process(pArr.shift());
}
function process(p) {
// 直接 return 的前提是 pArr 中不会有空元素
if (!p) {
processNext();
} else {
p.then(() => {
processNext();
});
}
}
function processNext() {
if (pArr.length > 0) {
// 代码关键:递归实现
process(pArr.shift());
}
}
}
function limitPromise(n = 3, pArr) {
for (let i = 0; i < n; i++) {
process(pArr.shift());
}
function process(p) {
// 直接 return 的前提是 pArr 中不会有空元素
if (!p) {
processNext();
} else {
p.then(() => {
processNext();
});
}
}
function processNext() {
if (pArr.length > 0) {
// 代码关键:递归实现
process(pArr.shift());
}
}
}
0 条评论
下一页