ECMAScript 6 及之后的几个版本逐步加大了对异步编程机制的支持,Promise(期约)是新增的引用类型,支持优雅地定义和组织异步逻辑。接下来几个版本增加了使用 async 和 await 关键字定义异步函数的机制。

注意,本章示例将大量使用异步日志输出的方式 setTimeout(console.log, 0, … params),旨在演示执行顺序及其他异步行为。异步输出的内容看起来虽然像是同步输出的,但实际上是异步打印的。这样可以让期约等返回的值达到其最终状态。
此外,浏览器控制台的输出经常能打印出 JavaScript 运行中无法获取的对象信息(比如期约的状态)。这个特性在示例中广泛使用,以便辅助读者理解相关概念。

1 INTRODUCTION TO ASYNCHRONOUS PROGRAMMING

The duality between synchronous and asynchronous behavior is a fundamental concept in computer science—especially in a single-threaded event loop model such as JavaScript. Asynchronous behavior is borne out of the need to optimize for higher computational throughput in the face of high-latency operations. If it is feasible to run other instructions while a computation is completing and still maintain a stable system, then it is pragmatic to do so.

Importantly, an asynchronous operation is not necessarily a computationally intensive or high-latency operation. It can be used anywhere it doesn’t make sense to block a thread of execution to wait for the asynchronous behavior to occur.

1.1 Synchronous vs. Asynchronous JavaScript

Synchronous behavior is analogous to sequential processor instructions in memory. Each instruction is executed strictly in the order in which it appears, and each is also capable of immediately retrieving information that is stored locally within the system (for example: in a processor register or in system memory). As a result, it is easy to reason about the program state (for example, the value of a variable) at any given point in code.

A trivial example of this would be performing a simple arithmetic operation:

let x = 3;
x = x + 4;

At each step in this program, it is possible to reason about the state of the program because execution will not proceed until the previous instruction is completed. When the last instruction completes, the computed value of x is immediately available for use.

This JavaScript snippet is easy to reason about because it is not difficult to anticipate what low-level instructions this will be compiled to (from JavaScript to x86, for example). Presumably, the operating system will allocate some memory for a floating point number on the stack, perform an arithmetic operation on that value, and write the result to that allocated memory. All of these instructions exist serially inside a single thread of execution. At each point in the compiled low-level program, you are
well-equipped to assert what can and cannot be known about the state of the system.

Conversely, asynchronous behavior is analogous to interrupts, where an entity external to the current process is able to trigger code execution. An asynchronous operation is often required because it is infeasible to force the process to wait a long time for an operation to complete (which is the case with a synchronous operation). This long wait might occur because the code is accessing a high-latency resource, such as sending a request to a remote server and awaiting a response.

A trivial JavaScript example of this would be performing an arithmetic operation inside a timeout:

let x = 3;
setTimeout(() => x = x + 4, 1000);

This program eventually performs the same work as the synchronous one—adding two numbers together—but this thread of execution cannot know exactly when the value of x will change because that depends on when the callback is dequeued from the message queue and executed.

This code is not as easy to reason about. Although the low-level instructions used in this example ultimately do the same work as the previous example, the second chunk of instructions (the addition operation and assignment) are triggered by a system timer, which will generate an interrupt to enqueue execution. Precisely when this interrupt will be triggered is a black box to the JavaScript runtime, so it effectively cannot be known exactly when the interrupt will occur (although it is guaranteed to be after the current thread of synchronous execution completes, since the callback will not yet have had an opportunity to be dequeued and executed). Nevertheless, you are generally unable to assert when the system state will change after the callback is scheduled.

For the value of x to become useful, this asynchronously executed function would need to signal to the rest of the program that it has updated the value of x. However, if the program does not need this value, then it is free to proceed and do other work instead of waiting for the result.

Designing a system to know when the value of x can be read is surprisingly tricky. Implementations of such a system within the JavaScript have undergone several iterations.

1.2 Legacy Asynchronous Programming Patterns

待补充 348

2 PROMISES

空缺的内容都没用。

2.2 Promise Basics

As of ECMAScript 6, Promise is a supported reference type and can be instantiated with the new operator. Doing so requires passing an executor function parameter (covered in an upcoming section), which here is an empty function object to please the interpreter:

let p = new Promise(() => {});
setTimeout(console.log, 0, p); // Promise <pending>

chrome中执行结果如下:

If an executor function is not provided, a SyntaxError will be thrown.

2.2.1 The Promise State Machine

When passing a promise instance to console.log, the console output (which may vary between browsers) indicates that this promise instance is pending. As mentioned previously, a promise is a stateful object that can exist in one of three states:

  • Pending
  • Fulfilled (sometimes also referred to as resolved)
  • Rejected

A pending state is the initial state a promise begins in. From a pending state, a promise can become settled by transitioning to a fulfilled state to indicate success, or a rejected state to indicate failure. This transition to a settled state is irreversible; once a transition to either fulfilled or rejected occurs, the state of the promise can never change. Furthermore, it is not guaranteed that a promise will ever leave the pending state. Therefore, well-structured code should behave properly if the promise successfully resolves, if the promise rejects, or if it never exits the pending state

Importantly, the state of a promise is private and cannot be directly inspected in JavaScript. The reason for this is primarily to prevent synchronous programmatic handling of a promise object based on its state when it is read. Furthermore, the state of a promise cannot be mutated by external JavaScript. This is for the same reason the state cannot be read: The promise intentionally encapsulates a block of asynchronous behavior, and external code performing synchronous definition of its
state would be antithetical to its purpose.

2.2.2 Resolved Values, Rejection Reasons, and Utility of Promises

There are two primary reasons the Promise construct is useful. The first is to abstractly represent a block of asynchronous execution. The state of the promise is indicative of whether or not the promise has yet to complete execution. The pending state indicates that execution has not yet begun or is still in progress. The fulfilled state is a nonspecific indicator that the execution has completed successfully. The rejected state is a nonspecific indicator that the execution did not complete successfully.

In some cases, the internal state machine is all the utility a promise needs to provide: the mere knowledge that a piece of asynchronous code has completed is sufficient for informing program flow. For example, suppose a promise is dispatching an HTTP request to a server. The request returning with a status of 200–299 might be sufficient to transition the promise state to fulfilled. Similarly, the request returning with a status that is not 200-299 would transition the promise state
to rejected.

In other cases, the asynchronous execution that the promise is wrapping is actually generating a value, and the program flow will expect this value to be available when the promise changes state. Alternately, if the promise rejects, the program flow will expect the reason for rejection when the promise changes state. For example, suppose a promise is dispatching an HTTP request to a server and expecting it to return JSON. The request returning with a status of 200–299 might be sufficient
to transition the promise to fulfilled, and the JSON string will be available inside the promise. Similarly, the request returning with a status that is not 200–299 would transition the promise state to rejected, and the reason for rejection might be an Error object containing the text accompanying the HTTP status code.

To support these two use cases, every promise that transitions to a fulfilled state has a private internal value. Similarly, every promise that transitions to a rejected state has a private internal reason. Both value and reason are an immutable reference to a primitive or object. Both are optional and will default to undefined. Asynchronous code that is scheduled to execute after a promise reaches a certain settled state is always provided with the value or reason

2.2.3 Controlling Promise State with the Executor

Because the state of a promise is private, it can only be manipulated internally. This internal manipulation is performed inside the promise’s executor function. The executor function has two primary duties: initializing the asynchronous behavior of the promise, and controlling any eventual state transition. Control of the state transition is accomplished by invoking one of its two function parameters, typically named resolve and reject. Invoking resolve will change the state to fulfilled; invoking reject will change the state to rejected. Invoking rejected() will also throw an error (this error behavior is covered more later).

let p1 = new Promise((resolve, reject) => resolve());
setTimeout(console.log, 0, p1); // Promise <resolved> let p2 = new Promise((resolve, reject) => reject());
setTimeout(console.log, 0, p2); // Promise <rejected>
// Uncaught error (in promise)

In the preceding example, there isn’t really any asynchronous behavior occurring because the state of each promise is already changed by the time the executor function exits. Importantly, the executor function will execute synchronously, as it acts as the initializer for the promise. This order of execution is demonstrated here:

new Promise(() => setTimeout(console.log, 0, 'executor'));
setTimeout(console.log, 0, 'promise initialized'); // executor
// promise initialized

You can delay the state transition by adding a setTimeout:

let p = new Promise((resolve, reject) => setTimeout(resolve, 1000));// When this console.log executes, the timeout callback has not yet executed:
setTimeout(console.log, 0, p); // Promise <pending>

Once either resolve or reject is invoked, the state transition cannot be undone. Attempts to further mutate the state will silently be ignored. This is demonstrated here:

let p = new Promise((resolve, reject) => { resolve();reject();  // No effect
}); setTimeout(console.log, 0, p); // Promise <resolved>

You can avoid promises getting stuck in a pending state by adding timed exit behavior. For example, you can set a timeout to reject the promise after 10 seconds:

let p = new Promise((resolve, reject) => { setTimeout(reject, 10000); // After 10 seconds, invoke reject()// Do executor things
}); setTimeout(console.log, 0, p);      // Promise <pending>
setTimeout(console.log, 11000, p);  // Check state after 11 seconds
// (After 10 seconds) Uncaught error
// (After 11 seconds) Promise <rejected>

Because a promise can only change state a single time, this timeout behavior allows you to safely set a maximum on the amount of time a promise can remain in the pending state. If the code inside the executor were to resolve or reject prior to the timeout, the timeout handler’s attempt to reject the promise will be silently ignored.

2.2.4 Promise Casting with Promise.resolve()

A promise does not necessarily need to begin in a pending state and utilize an executor function to reach a settled state. It is possible to instantiate a promise in the “resolved” state by invoking the Promise.resolve() static method. The following two promise instantiations are effectively equivalent:

let p1 = new Promise((resolve, reject) => resolve());
let p2 = Promise.resolve();

The value of this resolved promise will become the first argument passed to Promise.resolve(). This effectively allows you to “cast” any value into a promise:

setTimeout(console.log, 0, Promise.resolve());
// Promise <resolved>: undefined setTimeout(console.log, 0, Promise.resolve(3));
// Promise <resolved>: 3 // 多余的参数会忽略
setTimeout(console.log, 0, Promise.resolve(4, 5, 6));
// Promise <resolved>: 4

Perhaps the most important aspect of this static method is its ability to act as a passthrough when the argument is already a promise. As a result, Promise.resolve() is an idempotent method, as demonstrated here:

let p = Promise.resolve(7); setTimeout(console.log, 0, p === Promise.resolve(p));
// true setTimeout(console.log, 0, p === Promise.resolve(Promise.resolve(p)));
// true

This idempotence will respect the state of the promise passed to it:

let p = new Promise(() => {}); setTimeout(console.log, 0, p); // Promise <pending>
setTimeout(console.log, 0, Promise.resolve(p)); // Promise <pending> setTimeout(console.log, 0, p === Promise.resolve(p)); // true

Beware that this static method will happily wrap any non-promise, including an error object, as a resolved promise, which might lead to unintended behavior:

let p = Promise.resolve(new Error('foo')); setTimeout(console.log, 0, p);
// Promise <resolved>: Error: foo
2.2.5 Promise.reject()

与 Promise.resolve()类似,Promise.reject()会实例化一个拒绝的期约并抛出一个异步错误(这个错误不能通过 try/catch 捕获,而只能通过拒绝处理程序捕获)。下面的两个期约实例实际上是一样的:

let p1 = new Promise((resolve, reject) => reject());
let p2 = Promise.reject();

这个拒绝的期约的理由就是传给 Promise.reject()的第一个参数。这个参数也会传给后续的拒绝处理程序:

let p = Promise.reject(3);
setTimeout(console.log, 0, p); // Promise <rejected>: 3 p.then(null, (e) => setTimeout(console.log, 0, e)); // 3

关键在于,Promise.reject()并没有照搬 Promise.resolve()的幂等逻辑。如果给它传一个期约对象,则这个期约会成为它返回的拒绝期约的理由:

setTimeout(console.log, 0, Promise.reject(Promise.resolve()));
// Promise <rejected>: Promise <resolved>
2.2.6 同步/异步执行的二元性

同步/异步执行的二元性了这一点,其中包含了两种模式下抛出错误的情形:

try { throw new Error('foo');
} catch(e) { console.log(e); // Error: foo
} try { Promise.reject(new Error('bar'));
} catch(e) { console.log(e);
}
// Uncaught (in promise) Error: bar

第一个 try/catch 抛出并捕获了错误,第二个 try/catch 抛出错误却没有捕获到。乍一看这可能有点违反直觉,因为代码中确实是同步创建了一个拒绝的期约实例,而这个实例也抛出了包含拒绝理由的错误。这里的同步代码之所以没有捕获期约抛出的错误,是因为它没有通过异步模式捕获错误。从这里就可以看出期约真正的异步特性:它们是同步对象(在同步执行模式中使用),但也是异步执行模式的媒介。

在前面的例子中,拒绝期约的错误并没有抛到执行同步代码的线程里,而是通过浏览器异步消息队列来处理的。因此,try/catch 块并不能捕获该错误。代码一旦开始以异步模式执行,则唯一与之交互的方式就是使用异步结构——更具体地说,就是期约的方法。

2.3 Promise Instance Methods

The methods exposed on a promise instance serve to bridge the gap between the synchronous external code path and the asynchronous internal code path. These methods can be used to access data returned from an asynchronous operation, handle success and failure outcomes of the promise, serially evaluate promises, or add functions that only execute once the promise enters a terminal state.

2.3.1 Implementing the Thenable Interface

For the purposes of ECMAScript asynchronous constructs, any object that exposes a then() method is considered to implement the Thenable interface. The following is an example of the simplest possible class that implements this interface:

class MyThenable { then() {}
}

The ECMAScript Promise type implements the Thenable interface. This simplistic interface is not to be confused with other interfaces or type definitions in packages like TypeScript, which lay out a much more specific form of a Thenable interface.

2.3.2 Promise.prototype.then()

The method Promise.prototype.then() is the primary method that is used to attach handlers to a promise instance. The then() method accepts up to two arguments: an optional onResolved handler function, and an optional onRejected handler function. Each will execute only when the promise upon which they are defined reaches its respective “fulfilled” or “rejected” state.

function onResolved(id) { setTimeout(console.log, 0, id, 'resolved');
} function onRejected(id) { setTimeout(console.log, 0, id, 'rejected');
} let p1 = new Promise((resolve, reject) => setTimeout(resolve, 3000));
let p2 = new Promise((resolve, reject) => setTimeout(reject, 3000));p1.then(() => onResolved('p1'), () => onRejected('p1'));
p2.then(() => onResolved('p2'), () => onRejected('p2'));
//(3 秒后)
// p1 resolved
// p2 rejected

Because a promise can only transition to a final state a single time, you are guaranteed that execution of these handlers is mutually exclusive.

As described earlier, both handler arguments are completely optional. Any non-function type provided as an argument to then() will be silently ignored. If you wish to explicitly provide only an onRejected handler, providing undefined as the onResolved argument is the canonical choice. This allows you to avoid creating a temporary object in memory just to be ignored by the interpreter, and it will also please type systems that expect an optional function object as an argument.

function onResolved(id) { setTimeout(console.log, 0, id, 'resolved');
} function onRejected(id) { setTimeout(console.log, 0, id, 'rejected');
} let p1 = new Promise((resolve, reject) => setTimeout(resolve, 3000));
let p2 = new Promise((resolve, reject) => setTimeout(reject, 3000)); // Non-function handlers are silently ignored, not recommended
p1.then('gobbeltygook');// Canonical form of explicit onResolved handler skipping
p2.then(null, () => onRejected('p2')); // p2 rejected(3 秒后)

The Promise.prototype.then() method returns a new promise instance:

let p1 = new Promise(() => {});
let p2 = p1.then();
setTimeout(console.log, 0, p1); // Promise <pending>
setTimeout(console.log, 0, p2); // Promise <pending>
setTimeout(console.log, 0, p1 === p2); // false

This new promise instance is derived from the return value of the onResolved handler. The return value of the handler is wrapped in Promise.resolve() to generate a new promise. If no handler function is provided, the method acts as a passthrough for the initial promise’s resolved value. If there is no explicit return statement, the default return value is undefined and wrapped in a Promise.resolve().

let p1 = Promise.resolve('foo'); // Calling then() with no handler function acts as a passthrough
let p2 = p1.then();
setTimeout(console.log, 0, p2); // Promise <resolved>: foo // These are equivalent
let p3 = p1.then(() => undefined);
let p4 = p1.then(() => {});
let p5 = p1.then(() => Promise.resolve()); setTimeout(console.log, 0, p3); // Promise <resolved>: undefined
setTimeout(console.log, 0, p4); // Promise <resolved>: undefined
setTimeout(console.log, 0, p5); // Promise <resolved>: undefined

Explicit return values are wrapped in Promise.resolve():

...
// These are equivalent:
let p6 = p1.then(() => 'bar');
let p7 = p1.then(() => Promise.resolve('bar')); setTimeout(console.log, 0, p6); // Promise <resolved>: bar
setTimeout(console.log, 0, p7); // Promise <resolved>: bar // Promise.resolve() preserves the returned promise
let p8 = p1.then(() => new Promise(() => {}));
let p9 = p1.then(() => Promise.reject());
// Uncaught (in promise): undefined setTimeout(console.log, 0, p8); // Promise <pending>
setTimeout(console.log, 0, p9); // Promise <rejected>: undefined

Throwing an exception will return a rejected promise:

... let p10 = p1.then(() => { throw 'baz'; });
// Uncaught (in promise) baz setTimeout(console.log, 0, p10); // Promise <rejected> baz

Importantly, returning an error will not trigger the same rejection behavior, and will instead wrap the error object in a resolved promise:

... let p11 = p1.then(() => Error('qux')); setTimeout(console.log, 0, p11); // Promise <resolved>: Error: qux

The onRejected handler behaves in the same way: values returned from the onRejected handler are wrapped in Promise.resolve(). This might seem counterintuitive at first, but the onRejected handler is doing its job to catch an asynchronous error. Therefore, this rejection handler completing execution without throwing an additional error should be considered expected promise behavior and therefore return a resolved promise.

The following code snippet is the Promise.reject() analog of the previous examples using Promise.resolve():

let p1 = Promise.reject('foo'); // Calling then() with no handler function acts as a passthrough
let p2 = p1.then();
// Uncaught (in promise) foo
setTimeout(console.log, 0, p2); // Promise <rejected>: foo // These are equivalent
let p3 = p1.then(null, () => undefined);
let p4 = p1.then(null, () => {});
let p5 = p1.then(null, () => Promise.resolve()); setTimeout(console.log, 0, p3); // Promise <resolved>: undefined
setTimeout(console.log, 0, p4); // Promise <resolved>: undefined
setTimeout(console.log, 0, p5); // Promise <resolved>: undefined // These are equivalent
let p6 = p1.then(null, () => 'bar');
let p7 = p1.then(null, () => Promise.resolve('bar')); setTimeout(console.log, 0, p6); // Promise <resolved>: bar
setTimeout(console.log, 0, p7); // Promise <resolved>: bar // Promise.resolve() preserves the returned promise
let p8 = p1.then(null, () => new Promise(() => {}));
let p9 = p1.then(null, () => Promise.reject());
// Uncaught (in promise): undefined setTimeout(console.log, 0, p8); // Promise <pending>
setTimeout(console.log, 0, p9); // Promise <rejected>: undefined let p10 = p1.then(null, () => { throw 'baz'; });
// Uncaught (in promise) baz setTimeout(console.log, 0, p10); // Promise <rejected>: baz let p11 = p1.then(null, () => Error('qux')); setTimeout(console.log, 0, p11); // Promise <resolved>: Error: qux
2.3.3 Promise.prototype.catch()

The Promise.prototype.catch() method can be used to attach only a reject handler to a promise. It only takes a single argument, the onRejected handler function. The method is no more than syntactical sugar, and is no different than using Promise.prototype.then(null, onRejected).

The following code demonstrates this equivalence:

let p = Promise.reject();
let onRejected = function(e) {setTimeout(console.log, 0, 'rejected');
};// These two reject handlers behave identically:
p.then(null, onRejected); // rejected
p.catch(onRejected); // rejected

The Promise.prototype.catch() method returns a new promise instance:

let p1 = new Promise(() => {});
let p2 = p1.catch();
setTimeout(console.log, 0, p1); // Promise <pending>
setTimeout(console.log, 0, p2); // Promise <pending>
setTimeout(console.log, 0, p1 === p2); // false

With respect to creation of the new promise instance, Promise.prototype.catch() behaves identically to the onRejected handler of Promise.prototype.then().

3 异步函数

异步函数,也称为“async/await”(语法关键字),是 ES6 期约模式在 ECMAScript 函数中的应用。async/await 是 ES8 规范新增的。这个特性从行为和语法上都增强了 JavaScript,让以同步方式写的代码能够异步执行。下面是一个最简单的例子,这个期约在超时之后会解决为一个值:

let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));

这个期约在 1000 毫秒之后解决为数值 3。如果程序中的其他代码要在这个值可用时访问它,则需要写一个解决处理程序:

let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3)); p.then((x) => console.log(x)); // 3

这其实是很不方便的,因为其他代码都必须塞到期约处理程序中。不过可以把处理程序定义为一个函数:

function handler(x) { console.log(x); } let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3)); p.then(handler); // 3

这个改进其实也不大。这是因为任何需要访问这个期约所产生值的代码,都需要以处理程序的形式来接收这个值。也就是说,代码照样还是要放到处理程序里。ES8 为此提供了 async/await 关键字。

3.1 异步函数

ES8 的 async/await 旨在解决利用异步结构组织代码的问题。为此,ECMAScript 对函数进行了扩展,为其增加了两个新关键字:async 和 await。

3.1.1 async

async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头函数和方法上:

async function foo() {} let bar = async function() {}; let baz = async () => {}; class Qux { async qux() {}
}

使用 async 关键字可以让函数具有异步特征,但总体上其代码仍然是同步求值的。而在参数或闭包方面,异步函数仍然具有普通 JavaScript 函数的正常行为。正如下面的例子所示,foo()函数仍然会在后面的指令之前被求值:

async function foo() { console.log(1);
} foo();
console.log(2); // 1
// 2

不过,异步函数如果使用 return 关键字返回了值(如果没有 return 则会返回 undefined),这个值会被 Promise.resolve()包装成一个期约对象。异步函数始终返回期约对象。在函数外部调用这个函数可以得到它返回的期约:

async function foo() { console.log(1); return 3;
} // 给返回的期约添加一个解决处理程序
foo().then(console.log);
console.log(2);// 1
// 2
// 3

当然,直接返回一个期约对象也是一样的:

async function foo() { console.log(1); return Promise.resolve(3);
} // 给返回的期约添加一个解决处理程序
foo().then(console.log);
console.log(2);// 1
// 2
// 3

异步函数的返回值期待(但实际上并不要求)一个实现 thenable 接口的对象,但常规的值也可以。如果返回的是实现 thenable 接口的对象,则这个对象可以由提供给 then()的处理程序“解包”。如果不是,则返回值就被当作已经解决的期约。下面的代码演示了这些情况:

// 返回一个原始值
async function foo() { return 'foo';
}
foo().then(console.log);
// foo// 返回一个没有实现 thenable 接口的对象
async function bar() { return ['bar'];
}
bar().then(console.log);
// ['bar']// 返回一个实现了 thenable 接口的非期约对象
async function baz() { const thenable = { then(callback) { callback('baz'); } }; return thenable;
}
baz().then(console.log);
// baz// 返回一个期约
async function qux() { return Promise.resolve('qux');
}
qux().then(console.log);
// qux

与在期约处理程序中一样,在异步函数中抛出错误会返回拒绝的期约:

async function foo() { console.log(1); throw 3;
} // 给返回的期约添加一个拒绝处理程序
foo().catch(console.log);
console.log(2);// 1
// 2
// 3

不过,拒绝期约的错误不会被异步函数捕获:

async function foo() { console.log(1); Promise.reject(3);
} // Attach a rejected handler to the returned promise
foo().catch(console.log);
console.log(2); // 1
// 2
// Uncaught (in promise): 3

待补充 375

11 期约与异步函数相关推荐

  1. 学习笔记21—期约与异步函数

    目录 1 同步与异步 2 以往的异步编程模式 3 期约 4 期约的实例方法 3 非重入期约的方法 1 同步与异步 同步行为对应内存中顺序执行的处理器指令,每条指令都会严格按照它们出现的顺序来执行.相对 ...

  2. JavaScript:异步函数

    异步函数是 ES8 新增的,旨在解决利用异步结构组织代码的问题. 异步函数是 ECMAScript 对函数的扩展,是 ES6 期约在函数中的应用. 异步函数主要用于异步执行复杂任务,即执行时间较长的任 ...

  3. JavaScript异步函数Promise①——Promise筑基

    期约是对尚不存在的一个替身.期约(promise)这个名字最早是由 Daniel Friedman和 David Wise在他们于 1976 年发表的论文"The Impact of App ...

  4. python 全栈开发,Day43(python全栈11期月考题)

    python 全栈开发,Day43(python全栈11期月考题) python全栈11期月考题 1.常用字符串格式化有哪些?并说明他们的区别 2.请手写一个单例模式(面试题) 3.利用 python ...

  5. js异步函数(async/await)

    1.概念 异步函数也称为"asynac/await"(语法关键字),是ES6期约模式在ECMAScript函数中的应用.async/await是ES8新增的.这个特性让以同步方式写 ...

  6. 【码云周刊第 11 期】追踪代码大仓库? Git 的拿手好戏!

    为什么80%的码农都做不了架构师?>>>    一周热门资讯回顾 ActFramework 1.0 正式发布, Java MVC 框架 TIOBE 3 月编程语言排行榜:Swift ...

  7. 《强化学习周刊》第11期:强化学习应用之模拟到真实

    No.11 智源社区 强化学习组 强 化 学  习 研究 观点 资源 活动 关于周刊 强化学习作为人工智能领域研究热点之一,它在模拟到真实领域中的应用研究进展与成果也引发了众多关注.为帮助研究与工程人 ...

  8. 《预训练周刊》第11期:全球最大智能模型“悟道2.0”重磅发布、谷歌KELM:将知识图与语言模型预训练语料库集成...

    No.11 智源社区 预训练组 预 训 练 研究 观点 资源 活动 关于周刊 超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第11期&l ...

  9. javascript --- 异步函数的顺序进行

    假设我们希望某一组异步函数能一次进行,在不使用的任何工具的情况下,可能会编写出类似下面的代码: funcs[0](function() {funcs[1](function() {funcs[2](o ...

最新文章

  1. 【Python】Python学习----第一模块笔记
  2. 《R语言游戏数据分析与挖掘》一导读
  3. E数据结构实验之查找五:平方之哈希表
  4. @Autowired 注释的作用和用法
  5. Redis --数据类型 [1]
  6. vmware安装centos8步骤
  7. c语言考试常考试卷,c语言面试最必考的十道试题,求职必看!!!
  8. saltstack之keepalived的安装配置
  9. java堆 数据结构 堆_快速堆数据结构
  10. 使用new调用构造器创建对象并统一添加属性的代码运行过程
  11. 字符集在本地化过程中的影响
  12. 【阿里妈妈营销科学系列】第四篇:营销渠道效果评估与归因
  13. python求15 17 23 65 97的因数_pythonlearning
  14. 幼儿-综合素质【8】
  15. el-upload 上传 照片墙上传照片,上传一张之后,上传框就消失
  16. ORA-29491: invalid table for chunking 错误记录
  17. 如何选择一款适合你的外贸管理软件
  18. java毕业设计旅游分享系统源码+lw文档+mybatis+系统+mysql数据库+调试
  19. MODIS数据介绍和下载总结
  20. 中国软件欧美出口工程名单:金蝶等入选第一梯队

热门文章

  1. 【Java】-初识java
  2. GitHub报错master-master(fetch first)的解决方法
  3. 红外光学雨量传感器的工作原理
  4. 用Python代码画一只喜羊羊
  5. 英特尔在2011台北国际电脑展
  6. mysql数据库报错1067_mysql数据库 1067
  7. 软件需求分析期末考试
  8. 用vscode写java
  9. Hash,位图,布隆过滤器
  10. Android 无 EditText 情况下接受扫码枪扫描数据