Window callback function javascript

Callback for a popup window in JavaScript

But I want to achieve it in a systematic way, having a callback defined for this popup; something like:

var wnd = window.open(. ) wnd.callback = function(value) < console.log(value); >; 

I’ve tried defining the callback property in popup window JS code:

Unfortunately, that does not work, as.

. returns just that «null» I set initially.

I’ve also tried setting the callback in a parent window after window load (both thru window.onload=. and $(window).ready()), none worked.

I’ve also tried defining some method in child window source code to register callback internally:

function registerCallback(_callback) < callback = _callback; // also window.callback = _callback; >

And I don’t have any more ideas. Sure, it would be simple setting the value using window.opener, but I’ll loose much of a flexibility I need for this child window (actually an asset selector for DAM system).

If you have some ideas, please share them. Thank you a million!

2 Answers 2

HTML5’s postMessage comes to mind. It’s designed to do exactly what you’re trying to accomplish: post messages from one window and process it in another.

The caveat is that it’s a relatively new standard, so older browsers may not support this functionality.

To send a message from the source window:

window.postMessage("message", "*"); //'*' is the target origin, and should be specified for security 

To listen for messages in a target window:

window.addEventListener ("message", function(e) < console.log(e.data); //e.data is the string message that was sent. >, true); 

Thank you for your answer, but I’m afraid, I can’t go with partial IE support on this and as caniuse.com states, IE support is limited to frame/iframe only (even in IE10.0).

After few more hours of experiments, I think, I’ve found a viable solution for my problem.

The point is to reference jQuery from parent window and trigger a jQuery event on this window (I’m a Mac user but I suppose, jQuery has events working cross-platform, so IE compatibility is not an issue here).

This is my code for click handler on anchor.

$(this).find('a[x-special="select-asset"]').click(function() < var evt = jQuery.Event('assetSelect', < url: 'this is url', closePopup: true, >); var _parent = window.opener; _parent.jQuery(_parent.document).trigger(evt); >); 

. and this is the code of event handler:

$(document).bind('assetSelect', function (evt) < console.log(evt); >); 

This solution is fine, if you don’t need to distinguish between multiple instances of the asset selection windows (only one window will dispatch «assetSelect» event). I have not found a way to pass a kind of tag parameter to window and then pass it back in event.

Because of this, I’ve chosen to go along with (at the end, better and visually more pleasant) solution, Fancybox. Unfortunately, there is no way — by default — to distinguish between instances either. Therefore, I’ve extended Fancybox as I’ve described in my blog post. I’m not including the full text of blog post here, because is not the topic of this question.

Источник

Введение: колбэки

Эта функция загружает на страницу новый скрипт. Когда в тело документа добавится конструкция , браузер загрузит скрипт и выполнит его.

Вот пример использования этой функции:

// загрузит и выполнит скрипт loadScript('/my/script.js');

Такие функции называют «асинхронными», потому что действие (загрузка скрипта) будет завершено не сейчас, а потом.

Если после вызова loadScript(…) есть какой-то код, то он не будет ждать, пока скрипт загрузится.

loadScript('/my/script.js'); // код, написанный после вызова функции loadScript, // не будет дожидаться полной загрузки скрипта // . 

Мы хотели бы использовать новый скрипт, как только он будет загружен. Скажем, он объявляет новую функцию, которую мы хотим выполнить.

Но если мы просто вызовем эту функцию после loadScript(…) , у нас ничего не выйдет:

loadScript('/my/script.js'); // в скрипте есть "function newFunction() " newFunction(); // такой функции не существует!

Действительно, ведь у браузера не было времени загрузить скрипт. Сейчас функция loadScript никак не позволяет отследить момент загрузки. Скрипт загружается, а потом выполняется. Но нам нужно точно знать, когда это произойдёт, чтобы использовать функции и переменные из этого скрипта.

Давайте передадим функцию callback вторым аргументом в loadScript , чтобы вызвать её, когда скрипт загрузится:

function loadScript(src, callback) < let script = document.createElement('script'); script.src = src; script.onload = () =>callback(script); document.head.append(script); >

Событие onload описано в статье Загрузка ресурсов: onload и onerror, оно в основном выполняет функцию после загрузки и выполнения скрипта.

Теперь, если мы хотим вызвать функцию из скрипта, нужно делать это в колбэке:

loadScript('/my/script.js', function() < // эта функция вызовется после того, как загрузится скрипт newFunction(); // теперь всё работает . >);

Смысл такой: вторым аргументом передаётся функция (обычно анонимная), которая выполняется по завершении действия.

Возьмём для примера реальный скрипт с библиотекой функций:

function loadScript(src, callback) < let script = document.createElement('script'); script.src = src; script.onload = () =>callback(script); document.head.append(script); > loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => < alert(`Здорово, скрипт $загрузился`); alert( _ ); // функция, объявленная в загруженном скрипте >);

Такое написание называют асинхронным программированием с использованием колбэков. В функции, которые выполняют какие-либо асинхронные операции, передаётся аргумент callback — функция, которая будет вызвана по завершению асинхронного действия.

Мы поступили похожим образом в loadScript , но это, конечно, распространённый подход.

Колбэк в колбэке

Как нам загрузить два скрипта один за другим: сначала первый, а за ним второй?

Первое, что приходит в голову, вызвать loadScript ещё раз уже внутри колбэка, вот так:

loadScript('/my/script.js', function(script) < alert(`Здорово, скрипт $загрузился, загрузим ещё один`); loadScript('/my/script2.js', function(script) < alert(`Здорово, второй скрипт загрузился`); >); >);

Когда внешняя функция loadScript выполнится, вызовется та, что внутри колбэка.

А что если нам нужно загрузить ещё один скрипт.

loadScript('/my/script.js', function(script) < loadScript('/my/script2.js', function(script) < loadScript('/my/script3.js', function(script) < // . и так далее, пока все скрипты не будут загружены >); >) >);

Каждое новое действие мы вынуждены вызывать внутри колбэка. Этот вариант подойдёт, когда у нас одно-два действия, но для большего количества уже не удобно. Альтернативные подходы мы скоро разберём.

Перехват ошибок

В примерах выше мы не думали об ошибках. А что если загрузить скрипт не удалось? Колбэк должен уметь реагировать на возможные проблемы.

Ниже улучшенная версия loadScript , которая умеет отслеживать ошибки загрузки:

function loadScript(src, callback) < let script = document.createElement('script'); script.src = src; script.onload = () =>callback(null, script); script.onerror = () => callback(new Error(`Не удалось загрузить скрипт $`)); document.head.append(script); >

Мы вызываем callback(null, script) в случае успешной загрузки и callback(error) , если загрузить скрипт не удалось.

loadScript('/my/script.js', function(error, script) < if (error) < // обрабатываем ошибку >else < // скрипт успешно загружен >>);

Опять же, подход, который мы использовали в loadScript , также распространён и называется «колбэк с первым аргументом-ошибкой» («error-first callback»).

  1. Первый аргумент функции callback зарезервирован для ошибки. В этом случае вызов выглядит вот так: callback(err) .
  2. Второй и последующие аргументы — для результатов выполнения. В этом случае вызов выглядит вот так: callback(null, result1, result2…) .

Одна и та же функция callback используется и для информирования об ошибке, и для передачи результатов.

Адская пирамида вызовов

На первый взгляд это рабочий способ написания асинхронного кода. Так и есть. Для одного или двух вложенных вызовов всё выглядит нормально.

Но для нескольких асинхронных действий, которые нужно выполнить друг за другом, код выглядит вот так:

loadScript('1.js', function(error, script) < if (error) < handleError(error); >else < // . loadScript('2.js', function(error, script) < if (error) < handleError(error); >else < // . loadScript('3.js', function(error, script) < if (error) < handleError(error); >else < // . и так далее, пока все скрипты не будут загружены (*) >>); > >) > >);
  1. Мы загружаем 1.js . Продолжаем, если нет ошибок.
  2. Мы загружаем 2.js . Продолжаем, если нет ошибок.
  3. Мы загружаем 3.js . Продолжаем, если нет ошибок. И так далее (*) .

Чем больше вложенных вызовов, тем наш код будет иметь всё большую вложенность, которую сложно поддерживать, особенно если вместо . у нас код, содержащий другие цепочки вызовов, условия и т.д.

Иногда это называют «адом колбэков» или «адской пирамидой колбэков».

Пирамида вложенных вызовов растёт вправо с каждым асинхронным действием. В итоге вы сами будете путаться, где что есть.

Такой подход к написанию кода не приветствуется.

Мы можем попытаться решить эту проблему, изолируя каждое действие в отдельную функцию, вот так:

loadScript('1.js', step1); function step1(error, script) < if (error) < handleError(error); >else < // . loadScript('2.js', step2); >> function step2(error, script) < if (error) < handleError(error); >else < // . loadScript('3.js', step3); >> function step3(error, script) < if (error) < handleError(error); >else < // . и так далее, пока все скрипты не будут загружены (*) >>;

Заметили? Этот код делает всё то же самое, но вложенность отсутствует, потому что все действия вынесены в отдельные функции.

Код абсолютно рабочий, но кажется разорванным на куски. Его трудно читать, вы наверняка заметили это. Приходится прыгать глазами между кусками кода, когда пытаешься его прочесть. Это неудобно, особенно, если читатель не знаком с кодом и не знает, что за чем следует.

Кроме того, все функции step* одноразовые, и созданы лишь только, чтобы избавиться от «адской пирамиды вызовов». Никто не будет их переиспользовать где-либо ещё. Таким образом, мы, кроме всего прочего, засоряем пространство имён.

Нужно найти способ получше.

К счастью, такие способы существуют. Один из лучших — использовать промисы, о которых рассказано в следующей главе.

Источник

JavaScript Callbacks

JavaScript functions are executed in the sequence they are called. Not in the sequence they are defined.

This example will end up displaying «Goodbye»:

Example

function myFirst() <
myDisplayer(«Hello»);
>

function mySecond() myDisplayer(«Goodbye»);
>

This example will end up displaying «Hello»:

Example

function myFirst() <
myDisplayer(«Hello»);
>

function mySecond() myDisplayer(«Goodbye»);
>

Sequence Control

Sometimes you would like to have better control over when to execute a function.

Suppose you want to do a calculation, and then display the result.

You could call a calculator function ( myCalculator ), save the result, and then call another function ( myDisplayer ) to display the result:

Example

function myDisplayer(some) <
document.getElementById(«demo»).innerHTML = some;
>

function myCalculator(num1, num2) let sum = num1 + num2;
return sum;
>

let result = myCalculator(5, 5);
myDisplayer(result);

Or, you could call a calculator function ( myCalculator ), and let the calculator function call the display function ( myDisplayer ):

Example

function myDisplayer(some) <
document.getElementById(«demo»).innerHTML = some;
>

function myCalculator(num1, num2) let sum = num1 + num2;
myDisplayer(sum);
>

The problem with the first example above, is that you have to call two functions to display the result.

The problem with the second example, is that you cannot prevent the calculator function from displaying the result.

Now it is time to bring in a callback.

JavaScript Callbacks

A callback is a function passed as an argument to another function.

Using a callback, you could call the calculator function ( myCalculator ) with a callback ( myCallback ), and let the calculator function run the callback after the calculation is finished:

Example

function myDisplayer(some) <
document.getElementById(«demo»).innerHTML = some;
>

function myCalculator(num1, num2, myCallback) let sum = num1 + num2;
myCallback(sum);
>

myCalculator(5, 5, myDisplayer);

In the example above, myDisplayer is a called a callback function.

It is passed to myCalculator() as an argument.

Note

When you pass a function as an argument, remember not to use parenthesis.

Right: myCalculator(5, 5, myDisplayer);

Wrong: myCalculator(5, 5, myDisplayer()) ;

Example

// Create an Array
const myNumbers = [4, 1, -20, -7, 5, 9, -6];

// Call removeNeg with a callback
const posNumbers = removeNeg(myNumbers, (x) => x >= 0);

// Display Result
document.getElementById(«demo»).innerHTML = posNumbers;

// Keep only positive numbers
function removeNeg(numbers, callback) const myArray = [];
for (const x of numbers) if (callback(x)) myArray.push(x);
>
>
return myArray;
>

In the example above, (x) => x >= 0 is a callback function.

It is passed to removeNeg() as an argument.

When to Use a Callback?

The examples above are not very exciting.

They are simplified to teach you the callback syntax.

Where callbacks really shine are in asynchronous functions, where one function has to wait for another function (like waiting for a file to load).

Asynchronous functions are covered in the next chapter.

Источник

Читайте также:  (.+)
Оцените статью