created at 2023/08/05 04:18:56
updated at 2023/08/05 04:58:09
函数作为参数传递给其他函数,传递的是函数的定义并不会立即执行,而是在将来特定的时机再去调用,这个函数就叫做回调函数。
函数也可以被另一个函数返回,接受函数做参数或返回另一个函数的函数称为高阶函数。
typescript
//回调
var foo = function () {
console.log('foo');
};
//高阶函数
function bar(cb: () => void) {
console.log('bar');
cb();
}
bar(foo);
//bar
//foo
箭头函数不会绑定 this,不会改变 this 的指向。
typescript
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet() {
console.log(`hi,my name is ${this.name}`);
}
greetDelay1(dalay: number) {
setTimeout(function () {
console.log(`hi,my name is ${this.name}`);
}, dalay);
}
greetDelay2(delay: number) {
setTimeout(() => {
console.log(`hi,my name is ${this.name}`);
}, delay);
}
}
var person = new Person('jack');
person.greet();
person.greetDelay1(1000);
person.greetDelay2(1000);
//hi,my name is jack
//hi,my name is undefined
//hi,my name is jack
编译为 JavaScript(ES5)
javascript
'use strict';
var Person = /** @class */ (function () {
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
console.log('hi,my name is '.concat(this.name));
};
Person.prototype.greetDelay1 = function (dalay) {
setTimeout(function () {
console.log('hi,my name is '.concat(this.name));
}, dalay);
};
Person.prototype.greetDelay2 = function (delay) {
var _this = this;
setTimeout(function () {
console.log('hi,my name is '.concat(_this.name));
}, delay);
};
return Person;
})();
var person = new Person('jack');
person.greet();
person.greetDelay1(1000);
person.greetDelay2(1000);
当编译箭头函数时,
TS
编译器会生成一个 this 别名,名为_this,这个别名保证 this 指向不会改变。
javascript
ajax1(url, () => {
ajax2(url, () => {
ajax3(url, () => {
doSomething();
});
});
});
回调地狱虽然将异步函数的执行顺序变为同步。但是这样的代码阅读性非常不好,可维护性也很差。
对异步操作结果的一个承诺。
链式调用
在 Promise 函数内并不需要 try...catch 语句,因为 Promise 会在有异常抛出的时候自动进入 rejected 状态
使用 Promise 可以更好地控制执行流程(并行,串行,瀑布流,混合),但是 Promise 最大的问题就是代码冗余,原来的异步任务被 Promise 封装了一下,不管什么操作都用 then。
在js中,如果调用一个函数,可以确定的是一旦这个函数开始执行,在它执行完成之前其他代码都不能执行。然而**生成器**解决了这一问题,它可能会在函数执行过程中将这个函数暂停一次或多次,并在随后回复它的执行。
一个生成器代表一个值的序列,生成器对象的接口只是一个迭代器,可以调用 next 函数使他产出结果。它可以借助 yield
或 return
停止函数运行。
typescript
function* generatorFunction() {
console.log('开始执行');
yield 'Hello, ';
console.log('暂停后再次执行');
yield 'World!';
return 'typescript';
}
let iterator = generatorFunction();
console.log(iterator.next());
console.log(iterator.next());
//开始执行
//{ value: 'Hello, ', done: false }
//暂停后再次执行
//{ value: 'World!', done: false }
//{ value: 'typescript',done:true}
现在我们可以控制函数的执行了。这样就算编写一个无限循环也不会导致栈溢出。
typescript
function* itera() {
var i = 1;
while (true) yield i++;
}
var i = itera();
console.log(i.next());
console.log(i.next());
console.log(i.next());
//{ value: '1',done:false}
//{ value: '2',done:false}
//{ value: '3',done:false}
生成器给了我们以同步的方式编写异步代码的可能性,只要我们在异步事件发生的时候调用生成器的 next 方法就能做到这一点。
通过 next 参数向生成器传值
javascript
function* gen() {
console.log('开始执行');
let res1 = yield 1;
console.log('中断后继续执行');
console.log(res1);
let res2 = yield 2;
console.log(res2);
console.log('执行结束');
return 3;
}
let iterator = gen();
console.log(iterator.next('first'));
console.log(iterator.next('second'));
console.log(iterator.next('third'));
//开始执行
//{ value: 1, done: false }
//中断后继续执行
//second
//{ value: 2, done: false }
//third
//执行结束
//{ value: 3, done: true }
async 是异步的简写,await 可以认为是 asyncwait 的简写。所以可以理解为 async 用于声明一个函数是异步的,而 await 用于等待这个异步函数执行完成。
javascript
async function testAsync() {
return 'hello async';
}
const r = testAsync();
console.log(r);
//Promise { 'hello async' }
可见,async 函数直接使用 return,async 会把这个返回值通过
Promise.resolve()
封装,之后返回的是一个Promise
对象。
javascript
r.then((rs) => {
console.log(rs); //hello async
});
如果 async 函数没有返回值,它会返回
Promise.resolve(undefined)
一般可以认为 await 等待的是一个表达式,表达式的计算结果是 Promise 对象或其他值。
javascript
function fn() {
return 'something';
}
async function testAsync() {
return Promise.resolve('hello async');
}
async function test() {
const v1 = await fn();
const v2 = await testAsync();
console.log(v1, v2);
}
test();
//something hello async
对于 fn 添加 await 似乎没有什么影响。但是如果是 Promise 对象,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式返回值。
javascript
//! 如果一个函数本身就返回Prominse对象,加async和不加async的区别:
//* 加了async之后外面得到的Promise对象并不是return的那一个
(() => {
let promise;
async function test() {
promise = new Promise((resolve) => resolve(0));
promise.mask = 'hello';
return promise;
}
const get = test();
console.log(promise === get); // false
console.log(promise.mask); // hello
console.log(get.mask); // undefined
})();
Promise 写法
javascript
function doThing1(n: any) {
return new Promise((resolve) => {
setTimeout(() => resolve(n + 200), n);
});
}
function doThing2(n: any) {
return new Promise((resolve) => {
setTimeout(() => resolve(n + 200), n);
});
}
function doSomething1() {
doThing1(100).then((res1) => {
doThing2(res1).then((res2) => {
console.log(res2);
});
});
}
doSomething1(); //500
async 和 await 写法
javascript
function doThing1(n: any) {
return new Promise((resolve) => {
setTimeout(() => resolve(n + 200), n);
});
}
function doThing2(n: any) {
return new Promise((resolve) => {
setTimeout(() => resolve(n + 200), n);
});
}
async function doSomething2() {
const res1 = await doThing1(100);
const res2 = await doThing2(res1);
console.log(res2);
}
doSomething2();
由此,async 和 await 特别像是一个生成器的写法,它可以控制函数的执行。