Як вярнуць адказ ад асінхроннага выкліку?

У мяне ёсць функцыя foo , якая робіць запыт Ajax. Як вярнуць адказ ад foo ?

Я паспрабаваў вярнуць значэнне з зваротнага выкліку success , а таксама прызначыць адказ лакальнай зменнай ўнутры функцыі і вярнуць яе, але ні адзін з гэтых спосабаў не вяртае адказ.

 function foo() { var result; $.ajax({ url: '...', success: function(response) { result = response; // return response; // <- I tried that one as well } }); return result; } var result = foo(); // It always ends up being `undefined`. 
4687
08 янв. зададзены Felix Kling 08 студз. 2013-01-08 20:06 '13 у 20:06 2013/01/08 20:06
@ 39 адказаў
  • 1
  • 2

→ Для больш агульнага тлумачэння асінхроннага паводзін на розных прыкладах см. Чаму мая пераменная не змяняецца пасля таго, як я змяніў яе ўнутры функцыі? - асінхронная спасылка на код

→ Калі вы ўжо зразумелі праблему, перайдзіце да магчымых рашэнням ніжэй.

гэтая праблема

A ў Ajax азначае асінхронны . Гэта азначае, што адпраўка запыту (ці, дакладней, атрыманне адказу) вымаецца з звычайнага патоку выканання. У вашым прыкладзе $.ajax вяртае адразу, а наступны аператар return result; , Выконваецца да таго, як функцыя, якую вы перадалі ў якасці success зваротнага выкліку, нават была выклікана.

Вось аналогія, якая, трэба спадзявацца, растлумачвае розніцу паміж сінхронным і асінхронным патокам:

сінхронны

Уявіце, што вы тэлефануеце аднаму і просіце яго знайсці нешта для вас. Хоць гэта можа заняць некаторы час, вы чакаеце па тэлефоне і глядзіце ў прастору, пакуль ваш сябар не дасць вам адказ, які вам патрэбны.

Тое ж самае адбываецца, калі вы робіце выклік функцыі, які змяшчае "нармальны" код:

 function findItem() { var item; while(item_not_found) { // search } return item; } var item = findItem(); // Do something with item doSomethingElse(); 

Нават калі для выканання findItem можа спатрэбіцца шмат часу, любы код, наступны пасля var item = findItem(); павінен чакаць, пакуль функцыя не верне вынік.

асінхронны

Вы тэлефануеце свайму сябру зноў па той жа прычыне. Але на гэты раз вы кажаце яму, што спяшайцеся, і ён павінен ператэлефанаваць вам на ваш мабільны тэлефон. Вы вешаеце трубку, выходзьце з хаты і робіце ўсё, што планавалі. Як толькі ваш сябар ператэлефануе вам, вы будзеце мець справу з інфармацыяй, якую ён вам даў.

Гэта менавіта тое, што адбываецца, калі вы робіце запыт Ajax.

 findItem(function(item) { // Do something with item }); doSomethingElse(); 

Замест чакання адказу выкананне працягваецца неадкладна і выконваецца аператар пасля выкліку Ajax. Каб у канчатковым выніку атрымаць адказ, вы дае функцыю, якая будзе выклікацца пасля атрымання адказу, зваротны выклік (заўважце што-небудзь, "ператэлефануеце"). Любы аператар, наступны за гэтым выклікам, выконваецца да выкліку зваротнага выкліку.


Рашэнне (s)

Прыміце асінхроннай прыроды JavaScript! Хоць некаторыя асінхронныя аперацыі прадастаўляюць сінхронныя аналагі (як і "Ajax"), іх звычайна не рэкамендуецца выкарыстоўваць, асабліва ў кантэксце браўзэра.

Чаму гэта дрэнна, спытаеце вы?

JavaScript запускаецца ў патоку карыстацкага інтэрфейсу браўзэра, і любы працяглы працэс блакуе карыстацкі інтэрфейс, што робіць яго неотзывчивым. Акрамя таго, існуе верхні мяжа часу выканання для JavaScript, і браўзэр спытае карыстальніка, ці працягваць выкананне або няма.

Усё гэта сапраўды дрэнны карыстацкі досвед. Карыстальнік не зможа сказаць, ці ўсё працуе нармальна ці не. Акрамя таго, эфект будзе горш для карыстальнікаў з павольным падключэннем.

Далей мы разгледзім тры розных рашэнні, якія будуюцца адзін на адным:

  • Абяцанні з async/await (ES2017 +, даступна ў старых браўзэрах, калі вы карыстаецеся транспарцёр або рэгенератар)
  • Зваротныя выклікі (папулярныя ў вузле)
  • Абяцанні з дапамогай then() (ES2015 +, даступна ў старых браўзэрах, калі вы карыстаецеся адну з мноства бібліятэк абяцанняў)

Усе тры даступныя ў бягучых браўзэрах і вузле 7+.


ES2017 +: абяцанні з async/await чаканнем

Версія ECMAScript, выпушчаная ў 2017 годзе, прадставіла падтрымку на ўзроўні сінтаксісу для асінхронных функцый. З дапамогай async і await вы можаце пісаць асінхронна ў "сінхронным стылі". Код ўсё яшчэ асінхронны, але яго лягчэй чытаць / разумець.

async/await грунтуецца на абяцаннях: async функцыя заўсёды вяртае абяцанне. await "разгортвае" абяцанне і альбо вынік у значэнні абяцанне было вырашаны з або выдае памылку, калі абяцанне было адхілена.

Важна: вы можаце выкарыстоўваць await толькі ўнутры async функцыі. Прама зараз, на вышэйшым узроўні await пакуль не падтрымліваецца, так што вы, магчыма, прыйдзецца зрабіць асінхроннай IIFE пачаць async кантэкст.

Вы можаце прачытаць больш аб async і await на MDN.

Вось прыклад, які заснаваны на затрымцы вышэй:

 // Using 'superagent' which will return a promise. var superagent = require('superagent') // This is isn't declared as 'async' because it already returns a promise function delay() { // 'delay' returns a promise return new Promise(function(resolve, reject) { // Only 'delay' is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } async function getAllBooks() { try { // GET a list of book IDs of the current user var bookIDs = await superagent.get('/user/books'); // wait for 3 seconds (just for the sake of this example) await delay(); // GET information about each book return await superagent.get('/books/ids='+JSON.stringify(bookIDs)); } catch(error) { // If any of the awaited promises was rejected, this catch block // would catch the rejection reason return null; } } // Start an IIFE to use 'await' at the top level (async function(){ let books = await getAllBooks(); console.log(books); })(); current user // Using 'superagent' which will return a promise. var superagent = require('superagent') // This is isn't declared as 'async' because it already returns a promise function delay() { // 'delay' returns a promise return new Promise(function(resolve, reject) { // Only 'delay' is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } async function getAllBooks() { try { // GET a list of book IDs of the current user var bookIDs = await superagent.get('/user/books'); // wait for 3 seconds (just for the sake of this example) await delay(); // GET information about each book return await superagent.get('/books/ids='+JSON.stringify(bookIDs)); } catch(error) { // If any of the awaited promises was rejected, this catch block // would catch the rejection reason return null; } } // Start an IIFE to use 'await' at the top level (async function(){ let books = await getAllBooks(); console.log(books); })(); 

Бягучыя версіі браўзэра і вузла падтрымліваюць async/await . Вы таксама можаце падтрымліваць больш старыя асяроддзя, пераўтварыўшы свой код у ES5 з дапамогай рэгенератара (або інструментаў, якія выкарыстоўваюць рэгенератар, такіх як Babel ).


Хай функцыі прымаюць зваротныя выклікі

Зваротны выклік - гэта проста функцыя, перададзеная іншай функцыі. Гэтая іншая функцыя можа выклікаць функцыю, перададзеную кожны раз, калі яна гатовая. У кантэксце асінхроннага працэсу зваротны выклік будзе выклікацца кожны раз, калі выконваецца асінхронны працэс. Звычайна вынік перадаецца адваротнага выкліку.

У прыкладзе з пытаннем вы можаце прымусіць foo прымаць зваротны выклік і выкарыстоўваць яго ў якасці success зваротнага выкліку. дык гэта

 var result = foo(); // Code that depends on 'result' 

становіцца

 foo(function(result) { // Code that depends on 'result' }); 

Тут мы вызначылі функцыю "inline", але вы можаце перадаць любую спасылку на функцыю:

 function myCallback(result) { // Code that depends on 'result' } foo(myCallback); 

Сам foo вызначаецца наступным чынам:

 function foo(callback) { $.ajax({ // ... success: callback }); } 

callback будзе спасылацца на функцыю, якую мы перадаем foo калі мы яе выклікаем, і мы проста перадаем яе на success . Г.зн. як толькі Ajax-запыт будзе паспяховым, $.ajax выкліча callback і перадасць адказ на зваротны выклік (на які можна спасылацца з дапамогай result , паколькі менавіта так мы вызначылі зваротны выклік).

Вы таксама можаце апрацаваць адказ, перш чым перадаць яго адваротнага выкліку:

 function foo(callback) { $.ajax({ // ... success: function(response) { // For example, filter the response callback(filtered_response); } }); } 

Напісанне кода з выкарыстаннем зваротных выклікаў прасцей, чым можа здацца. У рэшце рэшт, JavaScript у браўзэры моцна залежыць ад падзей (падзеі DOM). Атрыманне адказу Ajax - не што іншае, як падзея.
Складанасці могуць паўстаць, калі вам прыйдзецца працаваць са іншым кодам, але большасць праблем можна вырашыць, проста прадумаўшы паток прыкладання.


ES2015 +: абяцанні з then ()

Promise API - гэта новая функцыя ECMAScript 6 (ES2015), але ён ужо мае добрую падтрымку браўзэра . Ёсць таксама шмат бібліятэк, якія рэалізуюць стандартны API Promises і прадастаўляюць дадатковыя метады для спрашчэння выкарыстання і кампазіцыі асінхронных функцый (напрыклад, bluebird ).

Абяцанні з'яўляюцца кантэйнерамі для будучых каштоўнасцяў. Калі абяцанне атрымлівае значэнне (яно дазволена) ці калі яно адмененае (адхілена), яно паведамляе ўсiм сваіх "слухачоў", якія хочуць атрымаць доступ да гэтага значэння.

Перавага ў параўнанні з простымі зваротнымі выклікамі складаецца ў тым, што яны дазваляюць вам аддзяліць ваш код, і іх лягчэй складаць.

Вось просты прыклад выкарыстання абяцанні:

 function delay() { // 'delay' returns a promise return new Promise(function(resolve, reject) { // Only 'delay' is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } delay() .then(function(v) { // 'delay' returns a promise console.log(v); // Log the value once it is resolved }) .catch(function(v) { // Or do something else if it is rejected // (it would not happen in this example, since 'reject' is not called). }); 

У дачыненні да нашага выкліку Ajax мы маглі б выкарыстоўваць такія абяцанні:

 function ajax(url) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.onload = function() { resolve(this.responseText); }; xhr.onerror = reject; xhr.open('GET', url); xhr.send(); }); } ajax("/echo/json") .then(function(result) { // Code depending on result }) .catch(function() { // An error occurred }); 

Апісанне ўсіх пераваг, якія абяцаюць прапанаваць, выходзіць за рамкі гэтага адказу, але калі вы пішаце новы код, вы павінны сур'ёзна разгледзець іх. Яны забяспечваюць выдатную абстракцыю і падзел вашага кода.

Больш інфармацыі пра абяцанні: HTML5 - скалы - Абяцанні JavaScript

Заўвага: адкладзеныя аб'екты jQuery

Адкладзеныя аб'екты - гэта карыстацкая рэалізацыя абяцанняў у jQuery (да стандартызацыі API Promise). Яны паводзяць сябе амаль як абяцанні, але выстаўляюць крыху іншы API.

Кожны Ajax-метад jQuery ўжо вяртае "адкладзены аб'ект" (фактычна абяцанне адкладзенага аб'екта), які вы можаце проста вярнуць са сваёй функцыі:

 function ajax() { return $.ajax(...); } ajax().done(function(result) { // Code depending on result }).fail(function() { // An error occurred }); 

Заўвага: абяцанне атрымалася

Памятаеце, што абяцанні і адкладзеныя аб'екты - гэта проста кантэйнеры для будучай кошту, а не сама кошт. Напрыклад, выкажам здагадку, у вас было наступнае:

 function checkPassword() { return $.ajax({ url: '/password', data: { username: $('#username').val(), password: $('#password').val() }, type: 'POST', dataType: 'json' }); } if (checkPassword()) { // Tell the user they're logged in } 

Гэты код няправільна разумее вышэйпаказаныя праблемы асінхроннасці. У прыватнасці, $.ajax() ня замарожвае код, пакуль правярае старонку '/ password' на вашым серверы - ён адпраўляе запыт на сервер і, пакуль чакае, неадкладна вяртае аб'ект jQuery Ajax Deferred, а не адказ ад сервер. Гэта азначае, што аператар if будзе заўсёды атрымліваць гэты адкладзены аб'ект, апрацоўваць яго як true і дзейнічаць так, як калі б карыстальнік увайшоў у сістэму. Не добра.

Але выправіць гэта лёгка:

 checkPassword() .done(function(r) { if (r) { // Tell the user they're logged in } else { // Tell the user their password was bad } }) .fail(function(x) { // Tell the user something bad happened }); 

Не рэкамендуецца: сінхронныя выклікі "Ajax"

Як я ўжо казаў, некаторыя (!) Асінхроннага аперацыі маюць сінхронныя аналагі. Я не абараняю іх выкарыстанне, але для паўнаты карціны, вось як вы павінны выканаць сінхронны выклік:

без jQuery

Калі вы наўпрост карыстаецеся аб'ект XMLHTTPRequest , перадайце false якасці трэцяга аргументу .open .

JQuery

Калі вы выкарыстоўваеце jQuery , вы можаце ўсталяваць для параметру async значэнне false . Звярніце ўвагу, што гэтая опцыя састарэла пачынаючы з jQuery 1.8. Затым можна яшчэ выкарыстоўваць success зваротнага выкліку або доступу да responseText ўласцівасць аб'екта jqXHR :

 function foo() { var jqXHR = $.ajax({ //... async: false }); return jqXHR.responseText; } 

Калі вы карыстаецеся любы іншы метад jQuery Ajax, такі як $.get , $.getJSON і г.д., Вы павінны змяніць яго на $.ajax (паколькі вы можаце перадаваць толькі параметры канфігурацыі ў $.ajax ).

Сцеражыся! Немагчыма зрабіць сінхронны запыт JSONP . JSONP па сваёй прыродзе заўсёды асінхроннага (яшчэ адна прычына, каб нават не разглядаць гэтую опцыю).

5011
08 янв. адказ дадзены Felix Kling 08 студз. 2013-01-08 20:06 '13 у 20:06 2013/01/08 20:06

Калі вы не выкарыстоўваеце jQuery у сваім кодзе, гэты адказ для вас

Ваш код павінен быць чымсьці накшталт гэтага:

 function foo() { var httpRequest = new XMLHttpRequest(); httpRequest.open('GET', "/echo/json"); httpRequest.send(); return httpRequest.responseText; } var result = foo(); // always ends up being 'undefined' 

Фелікс Клинг выдатна справіўся з напісаннем адказу для людзей, якія выкарыстоўваюць jQuery для AJAX, я вырашыў даць альтэрнатыву для людзей, якія гэтага не робяць.

( Звярніце ўвагу, што для тых, хто выкарыстоўвае новы API fetch , Angular або promises, я дадаў яшчэ адзін адказ ніжэй )


Тое, з чым вы сутыкаецеся

Гэта кароткае рэзюмэ "Тлумачэнне праблемы" з іншага адказу, калі вы не ўпэўненыя, прачытаўшы гэта, прачытайце гэта.

A ў AJAX азначае асінхронны. Гэта азначае, што адпраўка запыту (ці, хутчэй, атрыманне адказу) вымаецца з звычайнага патоку выканання. У вашым прыкладзе .send вяртаецца неадкладна, а наступны аператар return result; выконваецца да таго, як функцыя, якую вы перадалі ў якасці success зваротнага выкліку, была нават называецца.

Гэта азначае, што калі вы вяртаецеся, слухач, які вы вызначылі, яшчэ не выканаў, што азначае, што якое вяртаецца вамі значэнне не было вызначана.

простая аналогія

 function getFive(){ var a; setTimeout(function(){ a=5; },10); return a; } 

(Fiddle)

Вяртаецца значэнне a роўна undefined , так як частка a=5 яшчэ не выканана. AJAX дзейнічае так, вы вяртаеце значэнне да таго, як сервер атрымаў магчымасць паведаміць вашаму браўзэру, што гэта за значэнне.

Адным з магчымых рашэнняў гэтай праблемы з'яўляецца паўторнае выкарыстанне кода, інфармаванне вашай праграмы пра тое, што рабіць, калі разлік завершаны.

 function onComplete(a){ // When the code completes, do this alert(a); } function getFive(whenDone){ var a; setTimeout(function(){ a=5; whenDone(a); },10); } 

Гэта называецца CPS . У асноўным, мы перадаем getFive дзеянне, якое неабходна выканаць, калі яно завяршаецца, мы паведамляем нашаму кодэксу, як рэагаваць, калі падзея завяршаецца (напрыклад, наш выклік AJAX або ў гэтым выпадку тайм-аўт).

выкарыстанне:

 getFive(onComplete); 

Які павінен папярэдзіць "5" на экране. (Fiddle) .

магчымыя рашэнні

border=0

У асноўным ёсць два спосабу рашэння гэтай праблемы:

  • Зрабіце выклік AJAX сінхронным (патэлефануеце яму SJAX).
  • Реструктурируйте свой код для правільнай працы з зваротнымі выклікамі.

1. Сінхронны AJAX - не рабіце гэтага !!

Што тычыцца сінхроннага AJAX, не рабіце гэтага! Адказ Felix выклікае некаторыя важкія аргументы на карысць таго, чаму гэта дрэнная ідэя. Падводзячы вынік, ён замарозіць браўзэр карыстальніка, пакуль сервер не верне адказ і не створыць вельмі дрэнны карыстацкі інтэрфейс. Вось яшчэ адно кароткае выклад MDN пра тое, чаму:

XMLHttpRequest падтрымлівае як сінхронную, так і асінхронных сувязь. Увогуле, аднак, асінхронныя запыты павінны быць пераважней сінхронных запытаў па меркаваннях прадукцыйнасці.

Карацей кажучы, сінхронныя запыты блакуюць выкананне кода ...... гэта можа выклікаць сур'ёзныя праблемы ...

Калі вам трэба гэта зрабіць, вы можаце перадаць сьцяг: Вось як:

 var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false); // `false` makes the request synchronous request.send(null); if (request.status === 200) {// That HTTP for 'ok' console.log(request.responseText); } 

2. Код рэструктурызацыі

Няхай ваша функцыя прымае зваротны выклік. У прыкладзе код foo можа быць зроблены для прыняцця зваротнага выкліку. Мы паведамім нашаму кодэксу, як рэагаваць, калі foo завяршаецца.

Такім чынам:

 var result = foo(); // code that depends on `result` goes here 

становіцца:

 foo(function(result) { // code that depends on `result` }); 

Тут мы перадалі ананімную функцыю, але мы маглі б проста перадаць спасылку на існуючую функцыю, зрабіўшы яе такой:

 function myHandler(result) { // code that depends on `result` } foo(myHandler); 

Для атрымання дадатковай інфармацыі аб тым, як выконваецца гэты від зваротнага выкліку, праверце адказ Felix.

Зараз давайце вызначым foo сам, каб дзейнічаць адпаведна

 function foo(callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onload = function(){ // when the request is loaded callback(httpRequest.responseText);// we're calling our method }; httpRequest.open('GET', "/echo/json"); httpRequest.send(); } 

(скрыпка)

Цяпер наша функцыя foo прымае дзеянне, якое запускаецца, калі AJAX завяршаецца паспяхова, мы можам працягнуць гэтае, праверыўшы, не адказвае Ці статус адказу 200 і дзейнічае адпаведна (стварыце апрацоўшчык памылак і г.д.). Эфектыўнае рашэнне нашай праблемы.

Калі вам усё яшчэ цяжка зразумець гэта прачытаць кіраўніцтва па пачатку работы AJAX ў MDN.

953
30 мая '13 в 2:30 2013-05-30 02:30 адказ дадзены Benjamin Gruenbaum 30 мая '13 у 2:30 2013/05/30 02:30

XMLHttpRequest 2 (перш за ўсё прачытайце адказы Бенджаміна Грюнбаума і Фелікса Клинга )

Калі вы не выкарыстоўваеце jQuery і хочаце атрымаць добры кароткі XMLHttpRequest 2, які працуе ў сучасных браўзэрах, а таксама ў мабільных браўзэрах, я прапаную выкарыстоўваць яго наступным чынам:

 function ajax(a, b, c){ // URL, callback, just a placeholder c = new XMLHttpRequest; c.open('GET', a); c.onload = b; c.send() } 

Як вы бачыце:

  1. Гэта карацей, чым усе астатнія функцыі, пералічаныя.
  2. Зваротны выклік усталёўваецца наўпрост (таму ніякіх лішніх непатрэбных замыканняў).
  3. Ёсць некаторыя іншыя сітуацыі, якія я не памятаю, якія робяць XMLHttpRequest 1 раздражняльным.

Ёсць два спосабу атрымаць адказ на гэты выклік Ajax (тры з выкарыстаннем імя зменнай XMLHttpRequest):

найпросты:

 this.response 

Ці, калі па нейкай прычыне вы bind() зваротны выклік з класам:

 e.target.response 

прыклад:

 function callback(e){ console.log(this.response); } ajax('URL', callback); 

Або (вышэйпрыведзены лепш ананімныя функцыі заўсёды праблема):

 ajax('URL', function(e){console.log(this.response)}); 

Няма нічога прасцей.

Цяпер некаторыя людзі, верагодна, скажуць, што лепш выкарыстоўваць onreadystatechange ці нават імя зменнай XMLHttpRequest. Гэта не правільна.

Азнаёмцеся з пашыранымі функцыямі XMLHttpRequest

Падтрымліваюцца ўсе * сучасныя браўзэры. І я магу пацвердзіць, што я выкарыстоўваю гэты падыход, паколькі існуе XMLHttpRequest 2. У мяне ніколі не было ніякіх праблем ва ўсіх браўзэрах, якія я выкарыстоўваю.

onreadystatechange карысны, толькі калі вы хочаце атрымаць загалоўкі ў стане 2.

Выкарыстанне імя зменнай XMLHttpRequest з'яўляецца яшчэ адной вялікай памылкай, паколькі вам трэба выканаць зваротны выклік ўнутры замыканняў onload / oreadystatechange, інакш вы яго страцілі.


Цяпер, калі вы хочаце нешта больш складанае, выкарыстоўваючы post і FormData, вы можаце лёгка пашырыць гэтую функцыю:

 function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder c = new XMLHttpRequest; c.open(e||'get', a); c.onload = b; c.send(d||null) } 

Зноў жа ... гэта вельмі кароткая функцыя, але яна атрымлівае і публікуе.

Прыклады выкарыстання:

 x(url, callback); // By default it get so no need to set x(url, callback, 'post', {'key': 'val'}); // No need to set post data set x(url, callback); // By default it get so no need to set x(url, callback, 'post', {'key': 'val'}); // No need to set post data 

Або перадайце поўны элемент формы ( document.getElementsByTagName('form')[0] ):

 var fd = new FormData(form); x(url, callback, 'post', fd); 

Або ўсталюеце некаторыя карыстацкія значэння:

 var fd = new FormData(); fd.append('key', 'val') x(url, callback, 'post', fd); 

Як бачыце, я не рэалізаваў сінхранізацыю ... гэта дрэнна.

Сказаўшы гэта ... чаму б не зрабіць гэта простым спосабам?


Як ужо згадвалася ў каментары, выкарыстанне error сінхронны цалкам парушае сэнс адказу. Які добры кароткі спосаб правільна выкарыстоўваць Ajax?

апрацоўшчык памылак

 function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder c = new XMLHttpRequest; c.open(e||'get', a); c.onload = b; c.onerror = error; c.send(d||null) } function error(e){ console.log('--Error--', this.type); console.log('this: ', this); console.log('Event: ', e) } function displayAjax(e){ console.log(e, this); } x('WRONGURL', displayAjax); 

У прыведзеным вышэй сцэнары ў вас ёсць апрацоўшчык памылак, які статычна вызначаны, таму ён не ставіць пад пагрозу функцыю. Апрацоўшчык памылак можа выкарыстоўвацца і для іншых функцый.

Але каб сапраўды вывесці памылку, адзіны спосаб - напісаць няправільны URL, і ў гэтым выпадку кожны браўзэр выдае памылку.