深入理解-JavaScript-回调函数

作者:Nilesh Sanyal翻译:疯狂的技术宅 原文:https://dzone.com/articles/ja... 未经允许严禁转载 JavaScript回调函数是成为一名成功的 JavaScript 开发人员必须要了解的一个重要概念。但是我相信,在阅读本文之后,你将能够克服以前使用回调方法遇到的所有障碍。 在开始之前,首先要确保我们对函数的理解是扎实的。 快速回顾:JavaScript 函数什么是函数?函数是在其中有一组代码的逻辑构件,用来执行特定任务。实际上为了易于调试和维护,函数允许以更有组织的方式去编写代码。函数还允许代码重用。 你只需定义一次函数,然后在需要时去调用它,而不必一次又一次地编写相同的代码。 声明一个函数现在,让我们看看如何在 javascript 中声明一个函数。 使用函数的构造函数: 在这种方法中,函数是在“函数”的构造函数的帮助下创建的。从技术上讲,这种方法比使用函数表达式语法和函数声明语句语法去声明函数的方法效率要低。使用函数表达式: 通常这种方法与变量分配相同。简而言之,函数主体被视为一个表达式,并且该表达式被分配给一个变量。使用这种语法定义的函数可以是命名函数或匿名函数。没有名称的函数被称为匿名函数。匿名函数是自调用的,这意味着它会自动调用起自身。这种行为也称为立即调用的函数表达式(IIFE)。 使用函数声明: 这种方法是 JavaScript 中常用的老派方法。在关键字“function”之后,你必须指定函数的名称。之后,如果函数接受多个参数或参数,也需要提及它们。虽然这部分是完全可选的。在函数体中,函数必须将一个值返回给调用方。遇到 return 语句后,该函数将会停止执行。在函数内部,参数将会充当局部变量。 同样,在函数内部声明的变量是该函数的局部变量。局部变量只能在该函数内访问,因此具有相同名称的变量可以轻松地用于不同的函数。 调用一个函数在下列任何一种情况下,将调用之前声明的函数: 发生事件时,例如,用户单击按钮,或者用户从下拉列表中选择某些选项等等。从 javascript 代码中调用该函数时。该函数可以自动调用,我们已经在匿名函数表达式中进行了讨论。() 运算符调用该函数。 什么是回调函数?按照 MDN 的描述:回调函数是作为参数传给另一个函数的函数,然后通过在外部函数内部调用该回调函数以完成某种操作。 让我用人话解释一下,回调函数是一个函数,将会在另一个函数完成执行后立即执行。回调函数是一个作为参数传给另一个 JavaScript 函数的函数。这个回调函数会在传给的函数内部执行。 在 JavaScript 中函数被看作是一类对象。对于一类对象,我们的意思是指数字、函数或变量可以与语言中的其他实体相同。作为一类对象,可以将函数作为变量传给其他函数,也可以从其他函数中返回这些函数。 可以执行这种操作的函数被称为高阶函数。回调函数实际上是一种模式。 “模式”一词表示解决软件开发中常见问题的某种行之有效的方法。最好将回调函数作为回调模式去使用。 为什么我们需要回调客户端 JavaScript 在浏览器中运行,并且浏览器的主进程是单线程事件循环。如果我们尝试在单线程事件循环中执行长时间运行的操作,则会阻止该过程。从技术上讲这是不好的,因为过程在等待操作完成时会停止处理其他事件。 例如,alert 语句被视为浏览器中 javascript 中的阻止代码之一。如果运行 alert,则在关闭 alert 对话框窗口之前,你将无法在浏览器中进行任何交互。为了防止阻塞长时间运行的操作,我们使用了回调。 让我们深入研究一下,以便使你准确了解在哪种情况下使用回调。 在上面的代码片段中,首先执行 getMessage()函数,然后执行 displayMessage() 。两者都在浏览器的控制台窗口中显示了一条消息,并且都立即执行。 在某些情况下,一些代码不会立即执行。例如,如果我们假设 getMessage() 函数执行 API 调用,则必须将请求发送到服务器并等待响应。这时我们应该如何处理呢? 如何使用回调函数我认为与其告诉你 JavaScript 回调函数的语法,不如在前面的例子中实现回调函数更好。修改后的代码段显示在下面的截图中。 为了使用回调函数,我们需要执行某种无法立即显示结果的任务。为了模拟这种行为,我们用 JavaScript 的 setTimeout() 函数。该函数会暂停两秒钟,然后在控制台窗口中显示消息“ Hi,there”。 ...

November 4, 2019 · 2 min · jiezi

12内存溢出与内存泄漏

内存溢出与内存泄露一、内存溢出一种程序运行出现的错误。当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误。 二、内存泄漏占用的内存没有及时释放。内存泄露积累多了就容易导致内存溢出。常见的内存泄露: 意外的全局变量。没有及时清理的计时器或回调函数。闭包// 1. 内存溢出var obj = {}for (var i = 0; i < 10000; i++) { obj[i] = new Array(10000000) console.log('-----')}// 2. 内存泄露// 意外的全局变量,没有加varfunction fn() { a = new Array(10000000) console.log(a)}fn()// 3. 没有及时清理的计时器或回调函数var intervalId = setInterval(function () { //启动循环定时器后不清理 console.log('----')}, 1000)// clearInterval(intervalId)// 4. 闭包function fn1() { var a = 4 function fn2() { console.log(++a) } return fn2}var f = fn1()f()// f = null

June 27, 2019 · 1 min · jiezi

你与弄懂promise之间可能只差这篇文章(二)

点我看看~话不多说,上源码:// 核心方法!核心方法!核心方法!也是最难懂的!—-STARTconst resolvePromise = (promise2, x, resolve, reject) => { if (promise2 === x) { return reject(new TypeError(“A promise cannot be resolved with itself”)) } if (x && (typeof x === “object” || typeof x === “function”)) { try { let then = x.then; if (typeof then === “function”) { then.call(x, y => { resolve(y); resolvePromise(promise2, y, resolve, reject); }, r => { reject(r); }) } else { resolve(x); } } catch (e) { reject(e) } } else { resolve(x) }};// 核心方法!核心方法!核心方法!也是最难懂的!—-END// Commitment就是class Commitment { constructor (executor) { this.status = “PENDING” this.value = void(0); this.reason = void(0); this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.status === “PENDING”) { this.status = “RESOLVED”; this.value = value; this.onResolvedCallbacks.forEach(cb => cb()) } } const reject = (reason) => { if (this.status === “PENDING”) { this.status = “REJECTED”; this.reason = reason; this.onRejectedCallbacks.forEach(cb => cb()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then (onResolvedFn, onRejectedFn) { let promise2, x; promise2 = new Promise((resolve, reject) => { if (this.status === “RESOLVED”) { setTimeout(() => { try { x = onResolvedFn(this.value); resolvePromise(promise2, x, resolve, reject); } catch(e) { reject(e) } }, 0) } if (this.status === “REJECTED”) { setTimeout(() => { try { x = onRejectedFn(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } if (this.status === “PENDING”) { this.onResolvedCallbacks.push(() => { setTimeout(() => { try { x = onResolvedFn(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { x = onRejectedFn(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }); } }); return promise2 } catch (onRejectedFn) { return this.then(null, onRejectedFn) } // 静态方法 static resolve (value) { return new Commitment((resolve, reject) => { resolve(value) }) } static reject (err) { return new Commitment((resolve, reject) => { reject(err) }) } static all () { let result = []; return new Commitment((resolve, reject) => { if (arguments.length === 0) { return reject(new TypeError(“undefined is not iterable (cannot read property Symbol(Symbol.iterator))”)) } else { let args = […arguments][0], result = []; let count = args.length, num = 0; for (let i = 0; i < count; i++) { let item = args[i]; try { let then = item.then; if (typeof then === “function”) { then.call(item, y => { num += 1; result[i] = y; if (num === count) { resolve(result) } }, r => { reject(r) }) } else { result[i] = item; if (num === count) { resolve(result) } } } catch (e) { reject(e) } } } }) } static race () { // 未完待续 }} ...

February 28, 2019 · 3 min · jiezi